【问题标题】:Entity-Framework auto update实体框架自动更新
【发布时间】:2023-04-06 08:31:01
【问题描述】:

我尝试在我的项目中实现实体框架!我的项目是基于插件的,所以我不知道我必须将哪个对象保存到数据库。

我已经这样实现了:

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 迁移来更新 数据库 (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)

EDIT2:

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

【问题讨论】:

  • 您的持久层似乎使用了错误的工具。您是否考虑过 noSQL 解决方案?
  • @raderick 这不是一个选项....
  • 您是否尝试过使用 Update-Database -Verbose 更新 powershell 或 nuget 包管理器控制台?另外,空引用是否指向迁移创建的新表?
  • 我不想用 powershell 做这个,对不起!

标签: c# entity-framework dynamic plugins


【解决方案1】:

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

解决方案:

首先,删除

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 配置他们的实体类型自己。

【讨论】:

  • 谢谢!!!这是工作!只有一个问题:如果插件被删除,我不希望 ef 删除表!你对此有什么想法吗?
  • 这是我提到的一个问题。如果您不注册实体类型,EF 会假定它已被删除。如果您没有设置上述选项(默认为false),则会出现异常。不幸的是,AFAIK 没有允许您离开现有表格的选项。所以你要么全有,要么一无所有:(
  • 为我工作,将 useSuppliedContext 参数参数传递给约定。
【解决方案2】:

运行:

Update-Database –Verbose

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

【讨论】:

    【解决方案3】:
    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();
    }
    

    【讨论】:

      【解决方案4】:

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

      EF 需要 DbSet 位于上下文类中,因此您需要动态生成 DatabaseContext 类(基于插件实体)、编译并加载它。 之后,您可以开始考虑迁移(自动或手动,允许或不允许数据丢失等)。
      同样使用您刚刚创建的 DatabaseContext 应该很简单(您应该能够通过标准DbContext 接口访问您的类)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-22
        • 1970-01-01
        • 1970-01-01
        • 2023-03-21
        • 1970-01-01
        相关资源
        最近更新 更多