实体框架自动更新

14

我尝试将Entity-Framework引入我的项目中!我的项目是基于插件的,因此我不知道要保存哪个对象到数据库中。

我已经这样实现:

public class DatabaseContext : DbContext
{
    public DatabaseContext() : base()
    {
        Database.Initialize(true);
    }

    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        foreach( PluginDto plugin in BackendContext.Current.PluginManager._plugins) {
            foreach(Type obj in plugin.plugin.getPluginDatabaseObjects())
            {
                Type typ = typeof(EntityTypeConfiguration<>).MakeGenericType(obj);

                List<MethodInfo> l = modelBuilder.GetType().GetMethods().ToList<MethodInfo>();

                MethodInfo m_Entitiy = modelBuilder.GetType().GetMethod("Entity").MakeGenericMethod(new Type[] { obj });
                var configObj = m_Entitiy.Invoke(modelBuilder, null);

                MethodInfo m_ToTable = configObj.GetType().GetMethod("ToTable", new Type[] { typeof(String) });
                m_ToTable.Invoke(configObj, new object [] { obj.Name }); 
            }
        }

        base.OnModelCreating(modelBuilder);
    }

}

但是,当我进行更改时,出现了以下异常:

'DatabaseContext'上下文的支持模型已自数据库创建以来发生更改。考虑使用Code First Migrations更新数据库(http://go.microsoft.com/fwlink/?LinkId=238269)。

这个错误是完全合乎逻辑的。数据库不同步,但我将如何获得更新?我已阅读了一些相关内容:

 var config = new DbMigrationsConfiguration<MyContext> { AutomaticMigrationsEnabled = true };
 var migrator = new DbMigrator(config);
 migrator.Update();

但我不知道如何正确使用它以及在哪里使用它!非常感谢!

编辑1: 当我尝试使用以下命令:Enable-Migrations –EnableAutomaticMigrations

我得到了这个错误:

System.NullReferenceException: Object reference not set to an instance of an object.
   at SOM.Backend.database.DatabaseContext.OnModelCreating(DbModelBuilder modelBuilder) in C:\Users\Flo\Documents\Visual Studio 2015\Projects\SOM\Backend\BackendService\BackendService\database\DatabaseContext.cs:line 26
   at System.Data.Entity.Internal.LazyInternalContext.CreateModelBuilder()
   at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
   at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
   at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
   at System.Data.Entity.Internal.LazyInternalContext.MarkDatabaseInitialized()
   at System.Data.Entity.Database.Initialize(Boolean force)
   at SOM.Backend.database.DatabaseContext..ctor() in C:\Users\Flo\Documents\Visual Studio 2015\Projects\SOM\Backend\BackendService\BackendService\database\DatabaseContext.cs:line 21
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Data.Entity.Infrastructure.DbContextInfo.CreateInstance()
   at System.Data.Entity.Infrastructure.DbContextInfo..ctor(Type contextType, DbProviderInfo modelProviderInfo, AppConfig config, DbConnectionInfo connectionInfo, Func`1 resolver)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState, Boolean calledByCreateDatabase)
   at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
   at System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration)
   at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Run()
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
   at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
   at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldInitialCreate(String language, String rootNamespace)
   at System.Data.Entity.Migrations.EnableMigrationsCommand.<>c__DisplayClass2.<.ctor>b__0()
   at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)

编辑2:

  <connectionStrings>
    <add name="DatabaseContext" providerName="System.Data.SqlServerCe.4.0" connectionString="Data Source=SOM_db.sdf;Max Database Size=1024" />
  </connectionStrings>

看起来你在使用错误的工具来处理持久层。你有考虑过使用noSQL解决方案吗? - Red
1
@raderick 这不是一个选项.... - Flo
你尝试过通过PowerShell或NuGet包管理器控制台更新吗?可以使用Update-Database -Verbose命令。 此外,空引用是否指向迁移创建的新表? - GaelSa
1
抱歉,我不想用PowerShell来完成这个任务! - Flo
4个回答

15

你所要求的是可行的,但有一些限制。

解决方案:

首先,移除

Database.Initialize(true);

在构造函数中。构造函数会被多次调用,包括迁移。

其次,创建一个类似这样的配置类

internal sealed class DataContextConfiguration : DbMigrationsConfiguration<DataContext>
{
    public DataContextConfiguration()
    {
        AutomaticMigrationsEnabled = true;
        AutomaticMigrationDataLossAllowed = true;
        ContextKey = "DataContext";
    }
}

然后将构造函数更改如下:

public DataContext()
{
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<DataContext, DataContextConfiguration>());
}

完成了。插件中的实体类型所对应的数据库表将自动被创建或更新。

概括来说,这基本上是使用启用自动迁移的标准Code First方法,但在OnModelCreating重写中从内部进行动态实体类型注册/配置。

限制:

  • 如果不设置AutomaticMigrationDataLossAllowed = true,当移除现有插件时,EF将生成异常,因为它不允许删除相应的表。如果这样做,插件表将被删除,因此如果再次添加插件,它将从零开始。

  • 插件实体只能使用数据注释进行配置。如果您想要给它们完全控制权,您可能需要更改插件接口,而不是使用实体类型,而是调用一些方法并传递DbModelBuilder,以便它们可以使用Fluent API自行配置其实体类型。


1
谢谢!它正常工作了!只有一个问题:如果插件被删除,我不想让 ef 删除表。你有任何想法吗? - Flo
2
这是我之前提到的一个问题。如果您不注册实体类型,EF 就会认为它已被删除。如果您不设置上述选项(默认为 false),则会出现异常。不幸的是,据我所知,没有选项可以让您保留现有的表格。所以你只能全盘接受或者什么都不得到 :( - Ivan Stoev
useSuppliedContext 参数设置为 true,对于我的情况起作用。 - Arthur Rizzo

1
public class myContext : DbContext
{
    public DbSet<myTable> myTables { get; set; }

    public myContext() : base("myConStr") { }

    public void UpdateDatabase()
    {
        var Migrator = new DbMigrator(new Migrations.Configuration(){ TargetDatabase = new DbConnectionInfo(this.Database.Connection.ConnectionString, "System.Data.SqlClient") });
        IEnumerable<string> PendingMigrations = Migrator.GetPendingMigrations();
        foreach (var Migration in PendingMigrations)
            Migrator.Update(Migration);
    }
}

static void Main(string[] args)
{
   var db = new myContext();
   db.UpdateDatabase();
}

1

运行:

Update-Database –Verbose

如果失败,请将消息粘贴为评论。

0

我认为使用这种方法,它永远不会与EF6一起工作。

EF需要DbSets在上下文类中,因此您需要根据插件实体动态生成DatabaseContext类,编译并加载它。 之后,您可以开始考虑迁移(自动或手动,带或不带数据丢失等)。 此外,使用刚创建的DatabaseContext应该很简单(您应该能够通过标准的DbContext接口访问您的类来完成所有操作)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接