2016-09-06 16 views
8

Próbuję wprowadzić Entity-Framework do mojego projektu! Mój projekt jest oparty na wtyczkach, więc nie wiem, który obiekt muszę zapisać w bazie danych.Automatyczna aktualizacja Entity-Framework

I wprowadziły go tak:

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

} 

ale pojawia się ten wyjątek, gdy daję zmiany:

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).

Ten błąd jest zupełnie logiczne. Baza danych jest niezsynchronizowana, ale w jaki sposób otrzymam aktualizację? Czytałem coś na ten temat:

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

Ale nie wiem jak i gdzie należy go używać poprawnie! Dziękuję bardzo!

Edit1: Kiedy próbuję: Enable-Migracje -EnableAutomaticMigrations

mam ten błąd:

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> 
+0

Wygląda na to, że używasz niewłaściwego narzędzia do swojej warstwy trwałości. Czy myślałeś o rozwiązaniach noSQL? –

+0

@raderick To nie jest opcja .... – Flo

+0

Czy próbowałeś aktualizacji Tought Powerhell lub konsoli menedżera pakietów Nuget, przy użyciu Update-Database -Verbose? Czy odwołanie zerowe wskazuje na nową tabelę utworzoną przez migrację? – GaelSa

Odpowiedz

5

To, o co prosisz, jest wykonalne, ale z pewnymi ograniczeniami.

Rozwiązanie:

Najpierw wyjmij

Database.Initialize(true); 

od konstruktora. Konstruktor jest nazywany wiele razy, , w tym migracje.

Po drugie, należy utworzyć klasę konfiguracji jak ten

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

Następnie zmień konstruktora następująco:

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

i gotowe. Tabele bazy danych dla typów jednostek z wtyczek zostaną automatycznie utworzone/zaktualizowane odpowiednio.

Podsumowując, zasadniczo jest to standardowe podejście Code First z włączonymi automatycznymi migracjami, ale z dynamiczną rejestracją/konfiguracją typu jednostki z wnętrza nadpisania OnModelCreating.

Ograniczenia:

  • Jeśli nie ustawić AutomaticMigrationDataLossAllowed = true, gdy istniejące wtyczki jest usuwana, EF wygeneruje wyjątek, ponieważ nie jest dozwolone, aby usunąć odpowiednie tabele. A jeśli to zrobisz, tabele wtyczek zostaną usunięte, więc jeśli wtyczka zostanie dodana ponownie, rozpocznie się od zera.

  • Elementy wtyczek można konfigurować tylko za pomocą adnotacji danych. Jeśli chcesz nadać im pełną kontrolę, prawdopodobnie będziesz musiał zmienić interfejs wtyczki i zamiast przyjmować typy jednostek, wywołać metodę i przekazać numer DbModelBuilder, aby mogli używać Fluent API do samodzielnego konfigurowania swoich typów jednostek.

+0

Dziękujemy! To działa! Tylko jedno pytanie: Nie chcę, aby ef usuwał tabele, jeśli wtyczka została usunięta! Czy masz jakiś pomysł? – Flo

+1

To jest problem, o którym wspomniałem. Jeśli nie zarejestrujesz typu jednostki, EF założy, że zostało usunięte. Jeśli nie ustawisz powyższej opcji (domyślnie "false"), otrzymasz wyjątek. Niestety AFAIK nie ma opcji, która pozwala opuścić istniejące tabele. Więc dostajesz wszystko albo nic :( –

+0

OK, dziękuję bardzo! – Flo

0

nie sądzę, że będzie kiedykolwiek pracuj z EF6 przy użyciu tego podejścia.

EF potrzebuje, aby DbSet były w klasie kontekstu, więc musisz generować klasę DatabaseContext w locie (w oparciu o wtyczki), skompilować i wczytać. Po tym możesz zacząć myśleć o migracji (automatycznej lub ręcznej, z lub bez zezwolenia na utratę danych itd.).
również za pośrednictwem swojego prostu stworzony DatabaseContext powinny być proste (powinny być w stanie zrobić wszystko, z dostępem do klasy poprzez standardową DbContext Interface)

1

Run:

Update-Database –Verbose 

Jeśli to się nie powiedzie, proszę wkleić wiadomości jako komentarz.