2012-02-02 13 views
21

Próbuję użyć migracji EF 4.3 z wieloma pierwszymi tekstami DbContext. Moja aplikacja jest podzielona na kilka wtyczek, które prawdopodobnie mają swój własny DbContext dotyczący swojej domeny. Aplikacja powinna korzystać z jednej bazy danych sql.EF 4.3 Auto-migracje z wieloma kontekstami DbContext w jednej bazie danych

Kiedy próbuję automatycznie migrować konteksty w pustej bazie danych, odnosi się to tylko do pierwszego kontekstu. Każdy inny kontekst wymaga ustawienia właściwości AutomaticMigrationDataLossAllowed na wartość true, ale następnie próbuje usunąć tabele poprzedniej.

Więc moje pytanie brzmi:

  • Jak mogę powiedzieć migracji konfigurację tylko opiekować tabelach określonych w ich odpowiednim kontekście i zostawić wszystkie inne?
  • Co to jest właściwy przepływ pracy w celu obsługi wielu DbContextów z automatyczną migracją w jednej bazie danych?

Dziękujemy!

+0

To bardzo interesujące pytanie. Zastanawiam się, czy obsługa wielu kontekstów była częścią przypadków użycia migracji. –

+2

Bardzo wątpię, że wiele kontekstów może działać z automatycznymi migracjami, ma na celu aktualizację db, aby wyglądał jak kontekst bez względu na wszystko. Możesz mieć więcej szczęścia w rozwijaniu wtyczek za pomocą migracji ręcznych, w oddzielnych bazach danych do generowania migracji, a następnie zastosować je wszystkie do tej samej bazy danych. – Betty

+0

W międzyczasie zajrzałem do zespołów EF 4.3 i mam także wątpliwości, czy ramy migracji mogą poradzić sobie z kilkoma kontekstami. Ale nie ma żadnego powodu technicznego, który mógłbym wymyślić. Po wprowadzeniu modelu EDM można go odróżnić od bazy danych, znaleźć istniejące tabele tabel, utworzyć lub zmienić i pozostawić scenariusz usunięcia przez ręczne migracje do użytkownika. –

Odpowiedz

6

Code First Migrations zakłada, że ​​istnieje tylko jedna konfiguracja migracji dla każdej bazy danych (i jeden kontekst dla każdej konfiguracji).

mogę myśleć o dwóch możliwych rozwiązań:

  1. Utwórz zbiorczą kontekst, który obejmuje wszystkie podmioty każdego kontekstu i odniesienie tego „super” kontekstowego z klasy konfiguracji migracje. W ten sposób wszystkie tabele zostaną utworzone w bazie danych użytkownika, ale dane będą dostępne tylko w tych, dla których zostały zainstalowane wtyczki.

  2. Użyj oddzielnych baz danych dla każdego kontekstu. Jeśli udostępniasz elementy między kontekstami, dodaj niestandardową migrację i zastąp połączenie CreateTable(...) wywoływaniem Sql("CREATE VIEW ..."), aby uzyskać dane z "początkowej" bazy danych jednostki.

Chciałbym wypróbować # 1, ponieważ zachowuje wszystko w jednej bazie danych. Możesz utworzyć oddzielny projekt w swoim rozwiązaniu, aby zawierać migracje i ten "super" kontekst. Wystarczy dodać projekt, odwołać się do wszystkich projektów wtyczek, utworzyć kontekst obejmujący wszystkie jednostki, a następnie wywołać funkcję Enable-Migrations w tym nowym projekcie. Po tym czasie wszystko powinno działać zgodnie z oczekiwaniami.

+5

Akceptuję tę odpowiedź, niezależnie od tego, czy tak naprawdę nie jest to odpowiedź na moje pytanie. Myślę, że projektowanie migracji do jednego kontekstu na bazę danych jest błędem. Z jednej strony każda starsza baza danych, która ma tabele, które nie są używane w kontekście, powoduje problemy. Z drugiej strony (nawet w przypadku wstępnie skompilowanych widoków) domena aplikacji z kontekstem obejmującym około 100 różnych encji trwa od wieków. Podział tego na mniejsze konteksty jest jak dotąd jedynym rozwiązaniem. –

+3

Moja oryginalna odpowiedź stała się nieco przestarzała. EF 6.0 usunęło ograniczenie jednego kontekstu kodu pierwszego na bazę danych. Rzeczy powinny "po prostu działać" w wersjach 6.0 i nowszych. – bricelam

3

Mam działającą witrynę z wieloma kontekstami za pomocą migracji. Jednak musisz użyć oddzielnej bazy danych dla każdego kontekstu, a wszystko to jest przenoszone z klasy * Configuration w przestrzeni nazw Migrations twojego projektu, więc na przykład CompanyDbContext wskazuje na Company.sdf przy użyciu CompanyConfiguration. update-database -configurationtypename CompanyConfiguration. Inny LogDbContext wskazuje na Log.sdf przy użyciu LogConfiguration, itp.

Czy przy tych pracach próbowałeś utworzyć 2 konteksty wskazujące na tę samą bazę danych i nakazując konstruktorowi modelu zignorować listę tabel w innym kontekście?

protected override void OnModelCreating(DbModelBuilder modelBuilder) 
{ 
    modelBuilder.Ignore<OtherContextsClass>(); 
    // more of these 
} 

Ponieważ migracje działają z ModelBuilder, może to być przydatne.

Brzydką alternatywą jest unikanie używania automatycznych migracji, generowanie migracji za każdym razem, a następnie ręczne przesiewanie i usuwanie niepożądanych stwierdzeń, a następnie uruchamianie ich, mimo że nic nie stoi na przeszkodzie, aby stworzyć proste narzędzie, które analizuje konteksty i generuje oświadczenia i czy poprawki migracji dla Ciebie.

+1

Dziękuję za odpowiedź. Ale niestety nie mogę podzielić bazy danych. Ale dałeś mi dobrą wskazówkę, aby wykorzystać wyjście automigracji jako podstawę dla ręcznych. –

+0

jakikolwiek pomysł, gdyby działał z wieloma schematami (np. Dbo)? – Betty

32

Oto, co możesz zrobić. bardzo prosta.

Możesz utworzyć klasę migracji dla każdego kontekstu. np.

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{ 
    public Configuration1(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace1"; 
    } 
} 

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{ 
    public Configuration2(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace2"; 
    } 
} 

Teraz dodajesz migrację. Nie musisz włączać migracji, ponieważ już zrobiłeś to z 2 klasy wyżej.

Add-Migration -configuration Configuration1 Context1Init 

Spowoduje to utworzenie skryptu migracji dla kontekstu1. twój może powtórzyć to dla innych Kontekstów.

Add-Migration -configuration Configuration2 Context2Init 

Aby zaktualizować bazę

Update-Database -configuration Configuration1 
Update-Database -configuration Configuration2 

Można to zrobić w dowolnej kolejności. Poza tym musisz upewnić się, że każda konfigacja jest wywoływana po kolei.

+0

Doskonały, powiedział "Proszę podać ten, którego należy użyć" i nie wiedziałem, jak to zrobić. Dzięki! – joshcomley

+1

Otrzymuję "wsparcie modelu zmieniło kontekst", kiedy próbuję użyć Context1 –

+2

mój Boże, to powinno być oznaczone jako odpowiedź !!! Dziękuję bardzo! Właśnie w przypadku, gdy mam go do pracy z tym rozwiązaniem na MVC 5 i EF 6 – oskar132

0

Mam pracę z ręcznymi migracjami, ale nie można przejść na niższą wersję, ponieważ nie można zlikwidować konfiguracji w tabeli __MigrationHistory. Jeśli spróbuję i obniżyć wersję, traktuję migracje z innych konfiguracji jako automatyczne, a ponieważ nie pozwalam na utratę danych, to się nie uda. Będziemy go używać tylko do aktualizacji, więc działa na nasze potrzeby.

Wydaje się, że jest to dość nieprzyjemne, jestem pewien, że nie byłoby trudno go wspierać, pod warunkiem, że nie było nakładania się DbContexts.

1

Ok, mam zmaga się z tym na dzień teraz i tutaj jest rozwiązanie dla tych, którzy szukają odpowiedzi ...

jestem przy założeniu, że większość ludzi czyta ten post tutaj, ponieważ mają dużą DbContext klasy z wieloma właściwościami DbSet <> i ładowanie trwa długo. Prawdopodobnie pomyślałeś, że to ma sens, powinienem podzielić kontekst, ponieważ nie będę używać wszystkich dbsets naraz, a załaduję tylko "częściowy" kontekst oparty na sytuacji, w której potrzebuję to. Rozdzielacie je, tylko po to, aby się przekonać, że migracje z Code First nie wspierają waszego sposobu myślenia rewolucyjnego.

Pierwszym krokiem musiało być podzielenie kontekstów, następnie dodano klasę MigrationConfiguration dla każdego nowego kontekstu, dodaliśmy łańcuchy połączeń o nazwach dokładnie takich samych, jak nowe klasy Context.

Potem próbowali uruchomiony niedawno rozstali się konteksty jeden po drugim, wykonując Add-Migration Context1 następnie robi update-Database -verbose ...

Wszystko wydawało się działać prawidłowo, ale można zauważyć, że każdy kolejny Migracja usunęła wszystkie tabele z poprzedniej migracji i opuściła tabele tylko od ostatniej migracji.

Dzieje się tak, ponieważ bieżący model migracji oczekuje pojedynczego dbContext na bazę danych i musi być dopasowany do lustra.

To, co próbowałem, a ktoś zaproponował, aby to zrobić, to stworzyć pojedynczy SuperContext, który zawiera wszystkie zestawy Db. Utwórz pojedynczą klasę konfiguracji migracji i uruchom ją. Pozostaw częściowe klasy kontekstu w miejscu i spróbuj je zainicjować i użyć. EF skarży się, że model wsparcia się zmienił. Ponownie, dzieje się tak dlatego, że EF porównuje częściowy kontekst dbcontext z podpisem kontekstu All-Sets, który pozostał po migracji Super Context.

Jest to poważna usterka w mojej opinii.

W moim przypadku zdecydowałem, że WYDAJność jest ważniejsza niż migracje. Tak więc, co robiłem, to po uruchomieniu w kontekście Super i miałem wszystkie tabele w miejscu, poszedłem do bazy danych i ręcznie usunięto tabelę _MigrationHistory.

Teraz mogę tworzyć i wykorzystywać moje Kontekstowe konteksty bez narzekania na EF. Nie znajduje się tabela MigrationHistory i po prostu przechodzi dalej, co pozwala mi mieć "częściowy" widok bazy danych.

Oczywiście chodzi o to, że wszelkie zmiany w modelu będą musiały być ręcznie propagowane do bazy danych, więc należy zachować ostrożność.

To zadziałało jednak dla mnie.

0

Z pewnością rozwiązanie powinno zostać zmodyfikowane przez zespół EntityFramework w celu zmiany interfejsu API w taki sposób, aby obsługiwał bezpośrednią modyfikację tabeli _MigrationHistory do wybranej nazwy tabeli, np. _MigrationHistory_Context1, dzięki czemu może obsłużyć modyfikację niezależnych elementów DbContext. W ten sposób wszystkie są traktowane osobno, a to zależy od programisty, aby upewnić się, że nazwy podmiotów nie kolidują. Wydaje się, że jest wiele osób, które podzielają moją opinię, że duplikat DbContext z odniesieniami do zestawu podmiotów jest fałszywym, nieekspozycyjnym sposobem radzenia sobie z rzeczami. Duplikaty DbContexts są nieskuteczne w przypadku rozwiązań modułowych (Prism lub podobnych).

1

Jak wspomniano powyżej, Brice, najbardziej praktycznym rozwiązaniem jest posiadanie 1 super DbContext dla każdej aplikacji/bazy danych.

Posiadanie tylko 1 DbContext dla całej aplikacji wydaje się być kluczową wadą techniczną i metodologiczną, ponieważ wpływa między innymi na modułowość. Ponadto, jeśli korzystasz z usług danych WCF, możesz użyć tylko 1 usługi danych na aplikację, ponieważ usługa DataService może mapować tylko na 1 DbContext. To znacznie zmienia architekturę.

Dodatkową zaletą jest to, że cały kod migracyjny związany z bazą danych jest scentralizowany.

1

Właśnie natknąłem się na ten problem i zdałem sobie sprawę z tego, że podzieliłem je na różne konteksty, polegało wyłącznie na grupowaniu powiązanych modeli w łatwe do opanowania części, a nie z jakiegokolwiek innego technicznego powodu. Zamiast tego zadeklarowałem swój kontekst jako klasę częściową, a teraz różne pliki kodu z różnymi modelami mogą dodawać DbSets do DbContext.

W ten sposób magia automigracyjna nadal działa.

0

Chcę, aby ludzie wiedzieli, że odpowiedź z tym poniżej jest dla mnie skuteczna, ale z jednym zastrzeżeniem: nie używaj linii MigrationsNamespace.

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{ 
     public Configuration1(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace1"; 
    } 
} 

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{ 
    public Configuration2(){ 
     AutomaticMigrationsEnabled = false; 
     MigrationsNamespace = "YourProject.Models.ContextNamespace2"; 
    } 
} 

Jednak miałem już 2 baz danych ustalonych z własnych określonych kontekstach tak znalazłem się coraz błąd mówiąc „namespace YourProject.Models ma już ContextNamespace1 zdefiniowana”.Stało się tak, ponieważ "MigrationsNamespace =" YourProject.Models.ContextNamespace2 ";" powodowało, że dbcontext został zdefiniowany w przestrzeni nazw YourProjects.Models dwa razy po tym, jak wypróbowałem Init (raz w pliku Context1Init migracji i raz tam, gdzie miałem to wcześniej zdefiniowane).

Więc stwierdziliśmy, że to, co musiałem zrobić w tym momencie był początek mojej bazy danych i migracje od zera (na szczęście nie mam danych Musiałem zachować) poprzez następujące kierunki tutaj: http://pawel.sawicz.eu/entity-framework-reseting-migrations/

Następnie Zmieniłem kod, aby NIE zawierał linii MigrationsNamespace.

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{ 
     public Configuration1(){ 
     AutomaticMigrationsEnabled = false; 
    } 
} 

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{ 
    public Configuration2(){ 
     AutomaticMigrationsEnabled = false; 
    } 
} 

Wtedy wpadłem konfigurację polecenie Add-Migration Configuration1 Context1Init ponownie i linia Update Database -konfigurację Configuration1 ponownie (dla mojej 2. kontekście zbyt), i wreszcie, wszystko wydaje się być obecnie pracuje świetnie.

Powiązane problemy