2011-12-30 14 views
31

Pracuję nad projektem, który może skończyć z wieloma wersjami/wariantami UI, ale do tej pory mam dwa podprojekty w moim rozwiązaniu Web - zawierające interfejs WWW z ASP.NET MVC . Projekt serwisowy to miejsce, w którym mam zdefiniowany kontekst i modele bazy danych.Miejsce do umieszczenia Database.SetInitializer

Moim celem jest posiadanie minimum lub prawdopodobnie brak odniesień do kodu specjalnego EF w moim projekcie internetowym. Chcę, aby był niezależny, więc kiedy przełączam biblioteki DLL z obsługą usługi (z powiedzmy SQL na XML lub MySQL) nie powinienem dokonywać wielu modyfikacji w moim projekcie MVC.

Jak to wygląda:

Project layout

Moje pytania są następujące: - do tej pory nie znalazłem przykład stosując Database.SetInitializer w innym miejscu niż Global.asax. Chciałbym umieścić ponowne utworzenie bazy danych, gdyby model został zmieniony w mojej fabrycznej klasie DatabaseContextProvider lub w klasie usług, która wyciąga dane z kontekstu i dostarcza je do interfejsu użytkownika z DTO. Czy są jakieś minusy tej lokalizacji? - Chciałbym, aby kontekst connectionString był konfigurowalny z plikiem Properties/Settings.settings - czy jest to uzasadnione?

Odpowiedz

14

Potrzebny byłby mechanizm wywoływania metody Database.SetInitializer przed pierwszym użyciem modelu DbContext. Dlatego zwykle wywoływany jest w pliku Global.asax.

Można utworzyć klasę metodą inicjalizacji w projekcie tm.Service i wywołać ją w metodzie Application_Start i umieścić w tej inicjalizacji metodę Database.SetInitializer.

Umożliwia dostarczenie ciągu połączenia z pliku ustawień.

8

Umieszczam go na konstruktorze DbContext i działa dla mnie.

public myDbContext() : base(connectionToDatabase) { 
     Database.SetInitializer<myDbContext>(null); 
    } 

Rozwiązanie powyżej będzie działać, ale nie jest tak skuteczny jak następujący kod:

protected void Application_Start() 
    { 
     Database.SetInitializer<myDbContext>(null); 
    } 

W moim przypadku nie mam odniesienie mojego DAL na UI i do tego powodem, dla którego zrobiłem, jest stworzenie konfiguracji EntityFramework i zarejestrowanie mojego ustawienia za pomocą refleksji.

protected void Application_Start() 
    {   
     EntityFrameworkConfig.RegisterSettings(); 
    } 


public static class EntityFrameworkConfig 
{ 
    public static void RegisterSettings() 
    { 
     // Use the file name to load the assembly into the current 
     // application domain. 
     Assembly a = Assembly.Load("MyAssembly"); 
     // Get the type to use. 
     Type myType = a.GetType("MyType"); 
     // Get the method to call. 
     MethodInfo myMethod = myType.GetMethod("MySettingsMethod"); 
     // Create an instance. 
     object obj = Activator.CreateInstance(MyType); 
     // Execute the method. 
     myMethod.Invoke(obj, null); 
    } 
} 

    public void Configurations() 
    { 
     //Other settings 
     Database.SetInitializer<myDbContext>(null); 
    } 

Updated

z Entity Framework 6, teraz można użyć NullDatabaseInitializer

Database.SetInitializer(new NullDatabaseInitializer<MyDbContext>()); 
+6

Potencjalnym problemem jest to, że można go wywołać za każdym razem, gdy skonstruowana jest klasa myDbContext, co równie dobrze może być przydatne przy każdym użyciu bazy danych. Wyobrażam sobie, że jest to dość kosztowna operacja i nie chcesz, żeby tak się stało. Korzystanie z Global.asax Application_Start lub Static Constructor w klasie DataContext gwarantuje, że kod jest wywoływany tylko raz, gdy aplikacja jest uruchomiona. – Holf

+0

Zgadzam się z Holfem, kod powinien znajdować się na application_start –

32

Aby uniknąć sprzęgła, wolałbym, aby nie ustawić inicjator zewnątrz zespołu, który zawiera DataContext. Dodałem więc konstruktor statyczny dla DataContext. W ten sposób każdy projekt odwołujący się do tego zestawu będzie korzystał z inicjatora bez jawnego ustawiania go, a inicjator jest ustawiany tylko raz dla każdego procesu.

static MyDataContext() 
{ 
    Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDataContext, Configuration>()); 
} 

Ciąg połączenia zostanie oczywiście pobrany z pliku konfiguracyjnego aplikacji.

+9

Nie jestem pewien, czy to dobry pomysł, ponieważ masz wtedy ścisłe powiązanie między 'DbContext' i inicjatorem. Zasady inicjowania zależą od kontekstu, np. do testów użyłbyś 'DropCreateDatabaseAlways' i do produkcji' CreateDatabaseIfNotExists' ... – Pragmateek

3

Firma Microsoft umożliwiła, w przypadku EF6, skonfigurowanie jednego inicjalizatora w kontekście bazy danych w pliku konfiguracyjnym aplikacji. Zobacz ostatnią sekcję na tej stronie Microsoft: https://msdn.microsoft.com/en-us/data/jj556606.aspx

To, podobnie jak podejście "Global.asax", ma tę przewagę, że np. projekty testów jednostkowych mogą używać innego inicjalizatora dla tego samego kontekstu bazy danych.

+0

Wierzę, że jest to jeden inicjator dla kontekstu, a nie dla bazy danych. Wiele kontekstów może działać na tym samym DB. –

+0

@DanielMackay Ale ja _did_ napisz "kontekst bazy danych"! Czy przypadkiem przeoczyłeś słowo "kontekst" z powodu zawijania linii bezpośrednio po słowie "baza danych"? –

+1

nie polecają konfiguracji, raczej mówią, że możesz to zrobić, a także zrobić to w kodzie. Dla nich możesz to zrobić w dowolny sposób. –

Powiązane problemy