Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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>
like image 205
Flo Avatar asked Sep 06 '16 12:09

Flo


1 Answers

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.

like image 154
Ivan Stoev Avatar answered Sep 21 '22 15:09

Ivan Stoev