Do tej pory DbContext
mam wrażenie, że a ma reprezentować twoją bazę danych, a zatem, jeśli twoja aplikacja korzysta z jednej bazy danych, potrzebujesz tylko jednej DbContext
.
Jednak niektórzy koledzy chcą podzielić obszary funkcjonalne na osobne DbContext
klasy.
Wierzę, że pochodzi to z dobrego miejsca - z chęci utrzymania kodu w czystości - ale wydaje się niestabilne. Mój żołądek mówi mi, że to zły pomysł, ale niestety moje przeczucie nie jest wystarczającym warunkiem do podjęcia decyzji projektowej.
Więc szukam:
A) konkretne przykłady, dlaczego może to być zły pomysł;
B) zapewnienia, że wszystko się uda.
entity-framework
ef-code-first
entity-framework-4.3
dbcontext
Josh Schultz
źródło
źródło
Odpowiedzi:
Możesz mieć wiele kontekstów dla pojedynczej bazy danych. Może to być przydatne na przykład, jeśli baza danych zawiera wiele schematów bazy danych i chcesz obsłużyć każdy z nich jako osobny, niezależny obszar.
Problem polega na tym, że najpierw chcesz użyć kodu do utworzenia bazy danych - może to zrobić tylko jeden kontekst w aplikacji. Sztuką tego jest zazwyczaj jeden dodatkowy kontekst zawierający wszystkie twoje jednostki, który jest używany tylko do tworzenia bazy danych. Rzeczywiste konteksty aplikacji zawierające tylko podzbiory twoich jednostek muszą mieć inicjator bazy danych ustawiony na null.
Istnieją inne problemy, które zobaczysz podczas korzystania z wielu typów kontekstu - na przykład typy jednostek współdzielonych i ich przekazywanie z jednego kontekstu do drugiego itp. Zasadniczo jest to możliwe, może uczynić twój projekt znacznie czystszym i oddzielić różne obszary funkcjonalne, ale ma swoje dodatkowe koszty.
źródło
Enable-Migrations -ContextTypeName MyContext -MigrationsDirectory Migrations\MyContextMigrations
działa teraz.Napisałem tę odpowiedź około cztery lata temu i moje zdanie się nie zmieniło. Ale od tego czasu nastąpił znaczny rozwój w dziedzinie mikrousług. Na końcu dodałem uwagi dotyczące mikrousług ...
Zastanowię się nad tym pomysłem, mając doświadczenie w świecie rzeczywistym, aby poprzeć mój głos.
Zostałem przeniesiony do dużej aplikacji, która miała pięć kontekstów dla jednej bazy danych. Ostatecznie usunęliśmy wszystkie konteksty oprócz jednego - wracając do jednego kontekstu.
Na początku pomysł wielu kontekstów wydaje się dobrym pomysłem. Możemy podzielić dostęp do danych na domeny i zapewnić kilka czystych, lekkich kontekstów. Brzmi jak DDD, prawda? Uprościłoby to nasz dostęp do danych. Kolejny argument przemawia za wydajnością, ponieważ uzyskujemy dostęp tylko do potrzebnego kontekstu.
Ale w praktyce, wraz z rozwojem naszej aplikacji, wiele naszych tabel łączyło relacje w różnych kontekstach. Na przykład zapytania do tabeli A w kontekście 1 wymagały również dołączenia do tabeli B w kontekście 2.
Pozostało nam kilka kiepskich wyborów. Możemy powielić tabele w różnych kontekstach. Próbowaliśmy tego. Stworzyło to kilka problemów z mapowaniem, w tym ograniczenie EF, które wymaga, aby każda jednostka miała unikalną nazwę. Skończyło się na tym, że w różnych kontekstach istniały byty Person1 i Person2. Można argumentować, że był to zły projekt z naszej strony, ale pomimo naszych najlepszych starań, tak właśnie nasza aplikacja wzrosła w prawdziwym świecie.
Próbowaliśmy także zapytać w obu kontekstach, aby uzyskać potrzebne dane. Na przykład nasza logika biznesowa zapytałaby o połowę tego, czego potrzebowała z kontekstu 1, a druga połowa z kontekstu 2. Miało to kilka poważnych problemów. Zamiast wykonać jedno zapytanie w jednym kontekście, musieliśmy wykonać wiele zapytań w różnych kontekstach. Ma to prawdziwy wpływ na wydajność.
W końcu dobrą wiadomością jest to, że łatwo było usunąć wiele kontekstów. Kontekst ma być lekkim przedmiotem. Nie sądzę więc, aby wydajność była dobrym argumentem dla wielu kontekstów. W prawie wszystkich przypadkach uważam, że pojedynczy kontekst jest prostszy, mniej skomplikowany i prawdopodobnie będzie działał lepiej, i nie będziesz musiał wdrożyć wielu obejść, aby go uruchomić.
Pomyślałem o jednej sytuacji, w której przydatne może być wiele kontekstów. Osobny kontekst może być wykorzystany do rozwiązania fizycznego problemu z bazą danych, w której faktycznie zawiera więcej niż jedną domenę. Idealnie byłoby, gdyby kontekst był jeden do jednego dla domeny, który byłby jeden do jednego dla bazy danych. Innymi słowy, jeśli zestaw tabel nie jest w żaden sposób powiązany z innymi tabelami w danej bazie danych, prawdopodobnie powinny zostać wyciągnięte do osobnej bazy danych. Zdaję sobie sprawę, że to nie zawsze jest praktyczne. Ale jeśli zestaw tabel jest tak różny, że możesz czuć się swobodnie, dzieląc je na osobną bazę danych (ale nie chcesz), to mogę zobaczyć argument za użyciem osobnego kontekstu, ale tylko dlatego, że w rzeczywistości istnieją dwie oddzielne domeny.
Jeśli chodzi o mikrousługi, jeden kontekst nadal ma sens. Jednak w przypadku mikrousług każda usługa miałaby swój własny kontekst, który zawiera tylko tabele bazy danych odpowiednie dla tej usługi. Innymi słowy, jeśli usługa x uzyskuje dostęp do tabel 1 i 2, a usługa y uzyskuje dostęp do tabel 3 i 4, każda usługa miałaby swój unikalny kontekst, który obejmuje tabele specyficzne dla tej usługi.
Interesują mnie twoje myśli.
źródło
Ten wątek właśnie pojawił się na StackOverflow, więc chciałem zaoferować kolejną „B) gwarancję, że wszystko będzie dobrze” :)
Robię to dokładnie za pomocą wzoru ograniczonego kontekstu DDD. Napisałem o tym w mojej książce Programming Entity Framework: DbContext i jest to temat 50-minutowego modułu w jednym z moich kursów na temat Pluralsight -> http://pluralsight.com/training/Courses/TableOfContents/efarchitecture
źródło
Rozróżnianie kontekstów poprzez ustawienie domyślnego schematu
W EF6 możesz mieć wiele kontekstów, po prostu określ nazwę domyślnego schematu bazy danych w
OnModelCreating
metodzie twojejDbContext
klasy pochodnej (gdzie jest konfiguracja Fluent-API). Będzie to działać w EF6:W tym przykładzie zostanie użyty „Klient” jako prefiks dla tabel bazy danych (zamiast „dbo”). Co ważniejsze, będzie także poprzedzać
__MigrationHistory
tabelę (-y), npCustomer.__MigrationHistory
. Możesz mieć więcej niż jedną__MigrationHistory
tabelę w jednej bazie danych, po jednej dla każdego kontekstu. Tak więc zmiany, które wprowadzisz dla jednego kontekstu, nie zadziorą z drugim.Podczas dodawania migracji określ w pełni kwalifikowaną nazwę swojej klasy konfiguracji (pochodną
DbMigrationsConfiguration
) jako parametr wadd-migration
poleceniu:Krótkie słowo na temat klawisza kontekstu
Zgodnie z tym artykułem MSDN „ Rozdział - Wiele modeli ukierunkowanych na tę samą bazę danych ” EF 6 prawdopodobnie poradziłby sobie z sytuacją, nawet gdyby
MigrationHistory
istniała tylko jedna tabela, ponieważ w tabeli znajduje się kolumna ContextKey do rozróżnienia migracji.Jednak wolę mieć więcej niż jedną
MigrationHistory
tabelę, określając domyślny schemat, jak wyjaśniono powyżej.Korzystanie z oddzielnych folderów migracji
W takim scenariuszu możesz również chcieć pracować z różnymi folderami „Migracja” w swoim projekcie. Możesz odpowiednio skonfigurować
DbMigrationsConfiguration
klasę pochodną, używającMigrationsDirectory
właściwości:Podsumowanie
Podsumowując, można powiedzieć, że wszystko jest wyraźnie oddzielone: konteksty, foldery migracji w projekcie i tabele w bazie danych.
Wybrałbym takie rozwiązanie, jeśli istnieją grupy podmiotów, które są częścią większego tematu, ale nie są powiązane (za pomocą kluczy obcych) ze sobą.
Jeśli grupy podmiotów nie mają ze sobą nic wspólnego, stworzyłbym osobną bazę danych dla każdego z nich, a także uzyskałbym do nich dostęp w różnych projektach, prawdopodobnie z jednym kontekstem w każdym projekcie.
źródło
Prosty przykład do osiągnięcia poniżej:
Po prostu określ zakres właściwości w głównym kontekście: (służy do tworzenia i utrzymywania bazy danych) Uwaga: Po prostu użyj opcji chronionych: (Obiekt nie jest tutaj ujawniany)
MonitorContext: tutaj ujawnij osobny byt
Model diagnostyczny:
Jeśli chcesz, możesz oznaczyć wszystkie jednostki jako chronione w głównym ApplicationDbContext, a następnie utwórz dodatkowe konteksty dla każdej separacji schematów.
Wszystkie używają tego samego ciągu połączenia, jednak używają osobnych połączeń, więc nie krzyżuj transakcji i zwracaj uwagę na problemy z blokowaniem. Ogólnie twoja separacja projektowa, więc i tak nie powinno się zdarzyć.
źródło
DbSet<x>
definicję. Robię to w częściowym dopasowaniu klasy do tego, co robi Projektant EF.Przypomnienie: jeśli łączysz wiele kontekstów, upewnij się, że wycinasz i wklejasz wszystkie funkcje z różnych
RealContexts.OnModelCreating()
do swojego singlaCombinedContext.OnModelCreating()
.Właśnie zmarnowałem czas na szukanie, dlaczego moje relacje kasowania kasowania nie zostały zachowane, tylko po to, aby odkryć, że nie przeniosłem
modelBuilder.Entity<T>()....WillCascadeOnDelete();
kodu z mojego prawdziwego kontekstu do mojego połączonego kontekstu.źródło
OtherContext.OnModelCreating()
z połączonego kontekstu?Mój żołądek powiedział mi to samo, kiedy natknąłem się na ten projekt.
Pracuję na bazie kodu, w której istnieją trzy konteksty dbContext do jednej bazy danych. 2 z 3 kontekstów db są zależne od informacji z 1 kontekstu db, ponieważ obsługuje on dane administracyjne. Ten projekt nałożył ograniczenia na sposób wysyłania zapytań do danych. Natknąłem się na ten problem polegający na tym, że nie można dołączyć do kontekstów dbcontext. Zamiast tego musisz wykonać zapytanie dwóch oddzielnych kontekstów db, a następnie wykonać połączenie w pamięci lub wykonać iterację w obu, aby uzyskać kombinację tych dwóch jako zestaw wyników. Problem polega na tym, że zamiast zapytania o konkretny zestaw wyników ładujesz teraz wszystkie swoje rekordy do pamięci, a następnie łączysz się z dwoma zestawami wyników w pamięci. To może naprawdę spowolnić.
Zadałbym pytanie „tylko dlatego, że możesz, prawda?„W
tym artykule opisano problem związany z tym projektem. Określone wyrażenie LINQ zawiera odwołania do zapytań powiązanych z różnymi kontekstami
źródło
Zainspirowany przez [@JulieLerman's DDD MSDN Mag Article 2013] [1]
źródło
Najpierw w kodzie możesz mieć wiele DBContext i tylko jedną bazę danych. Musisz tylko określić parametry połączenia w konstruktorze.
źródło
Kolejna odrobina „mądrości”. Mam bazę danych, zarówno Internet, jak i aplikację wewnętrzną. Mam kontekst dla każdej twarzy. To pomaga mi zachować zdyscyplinowaną i bezpieczną segregację.
źródło
Chcę udostępnić przypadek, w którym myślę, że możliwość posiadania wielu DBContexts w tej samej bazie danych ma sens.
Mam rozwiązanie z dwoma bazami danych. Jeden dotyczy danych domeny oprócz informacji o użytkowniku. Drugi służy wyłącznie do informacji o użytkowniku. Podział ten wynika przede wszystkim z ogólnego rozporządzenia UE o ochronie danych . Dzięki dwóm bazom danych mogę swobodnie przenosić dane domeny (np. Z platformy Azure do mojego środowiska programistycznego), o ile dane użytkownika pozostają w jednym bezpiecznym miejscu.
Teraz dla bazy danych użytkowników zaimplementowałem dwa schematy poprzez EF. Jednym z nich jest domyślny zapewniany przez platformę AspNet Identity. Druga to nasza własna implementacja wszystkiego, co związane jest z użytkownikiem. Wolę to rozwiązanie niż rozszerzenie schematu ApsNet, ponieważ mogę łatwo obsłużyć przyszłe zmiany w AspNet Identity, a jednocześnie separacja wyjaśnia programistom, że „nasza własna informacja o użytkowniku” mieści się w określonym schemacie użytkownika, który zdefiniowaliśmy .
źródło
Huh, spędziłem sporo czasu na problemie z osobnymi kontekstami DB dla każdego schematu DB, mam nadzieję, że pomoże to komuś innemu ...
Niedawno zacząłem pracować nad projektem, który miał jedną bazę danych z 3 schematami (pierwsze podejście DB), jedną z nich do zarządzania użytkownikami. Z każdego oddzielnego schematu wyodrębniono kontekst DB. Oczywiście użytkownicy byli również powiązani z innymi schematami, np. schemat KB miał tabelę Temat, który „utworzył”, „ostatnio zmodyfikował” itd. FK do schematu tożsamości, appuser tabeli.
Obiekty te zostały załadowane osobno w języku C #, po pierwsze temat został załadowany z 1 kontekstu, następnie użytkownicy zostali załadowani za pomocą identyfikatorów użytkowników z innego kontekstu db - nieźle, trzeba to naprawić! (podobnie do korzystania z wielu kontekstów db w tej samej bazie danych z EF 6 )
Najpierw próbowałem dodać brakujące instrukcje FK ze schematu tożsamości do schematu KB, do EF modelBuilder w kontekście KB DB. Tak samo, jakby był tylko 1 kontekst, ale oddzieliłem go do 2.
Nie działało, ponieważ kontekst bazy danych kb nie miał żadnych informacji o obiekcie użytkownika, postgres zwrócił błąd
relation "AppUsers" does not exist
. Instrukcja Select nie zawierała prawidłowych informacji o schemacie, nazwach pól itp.Prawie się poddałem, ale wtedy zauważyłem przełącznik „-d” podczas działania
dotnet ef dbcontext scaffold
. Jego skrót od -data-adnotations - Użyj atrybutów, aby skonfigurować model (tam, gdzie to możliwe). Jeśli zostanie pominięty, używany jest tylko płynny interfejs API. Po określeniu tego przełącznika właściwości obiektu zostały zdefiniowane nie w kontekście dbOnModelCreating()
, ale na samym obiekcie, z atrybutami.W ten sposób EF uzyskał wystarczające informacje do wygenerowania prawidłowej instrukcji SQL z prawidłowymi nazwami pól i schematami.
TL; DR: oddzielne konteksty DB nie radzą sobie dobrze z relacjami (FK) między nimi, każdy kontekst zawiera tylko informacje o swoich własnych bytach. Po włączeniu opcji „-data-adnotations”
dotnet ef dbcontext scaffold
informacje te nie są przechowywane w każdym osobnym kontekście, ale same obiekty DB.źródło