简体   繁体   中英

Entity-Framework auto update

i try to implement Entity-Framework into my project! My Project is plugin-based so i do not know which object i have to save to database.

I have implemented it so:

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);
    }

}

But i get this exception, when i give a change:

The model backing the 'DatabaseContext' context has changed since the database was created. Consider using Code First Migrations to update the database ( http://go.microsoft.com/fwlink/?LinkId=238269 ).

This error is completly logical. The database is out of sync, but how i will get the update? i Have read something about this:

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

But i don't know how and where to use it correctly! Thank you very much!

EDIT1: When i try to: Enable-Migrations –EnableAutomaticMigrations

I got this error:

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>

What are you asking for is doable, but with some limitations.

Solution:

First, remove the

Database.Initialize(true);

from the constructor. The constructor is called multiple times, including the migrations.

Second, create a configuration class like this

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

Then change the constructor as follows:

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

and you are done. The database tables for the entity types from the plugins will be automatically created/updated accordingly.

To recap, basically this is a standard Code First approach with automatic migrations enabled, but with dynamic entity type registration/configuration from inside the OnModelCreating override.

Limitations:

  • If you don't set AutomaticMigrationDataLossAllowed = true , when the existing plugin is removed, EF will generate exception because it is not allowed to delete the corresponding tables. And if you do so, the plugin tables will be deleted, so if the plugin is added again, it will start from zero.

  • The plugin entities can only be configured using Data Annotations. If you want to give them full control, you'd probably need to change the plugin interface and instead of taking the entity types, to call some method and pass the DbModelBuilder instead, so they can use Fluent API to configure their entity types themselves.

Run:

Update-Database –Verbose

If it fails, please paste the messages as a comment.

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();
}

I don't think that it will ever work with EF6 using this approach.

EF needs that the DbSets are on the context class so you need to generate your DatabaseContext class on the fly (basing on plugin entities), compile and load it. After that you can start thinking about migration (automatic or manual, with or without allowing data lossing and so on).
Also using your just created DatabaseContext should be simple (you should be able to do everything accessing to your class via standard DbContext interface)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM