Mein bisheriger Eindruck war, dass a DbContext
Ihre Datenbank darstellen soll. Wenn Ihre Anwendung also eine Datenbank verwendet, möchten Sie nur eine DbContext
.
Einige Kollegen möchten jedoch Funktionsbereiche in separate DbContext
Klassen aufteilen.
Ich glaube, das kommt von einem guten Ort - dem Wunsch, den Code sauberer zu halten -, aber es scheint volatil zu sein. Mein Bauch sagt mir, dass es eine schlechte Idee ist, aber leider ist mein Bauchgefühl keine ausreichende Voraussetzung für eine Designentscheidung.
Also suche ich:
A) konkrete Beispiele dafür, warum dies eine schlechte Idee sein könnte;
B) versichert, dass dies alles gut funktionieren wird.
entity-framework
ef-code-first
entity-framework-4.3
dbcontext
Josh Schultz
quelle
quelle
Antworten:
Sie können mehrere Kontexte für eine einzelne Datenbank haben. Dies kann beispielsweise nützlich sein, wenn Ihre Datenbank mehrere Datenbankschemata enthält und Sie jedes als separaten, eigenständigen Bereich behandeln möchten.
Das Problem ist, wenn Sie zuerst Code zum Erstellen Ihrer Datenbank verwenden möchten - dies kann nur ein einziger Kontext in Ihrer Anwendung. Der Trick hierfür ist normalerweise ein zusätzlicher Kontext, der alle Ihre Entitäten enthält und nur für die Datenbankerstellung verwendet wird. In Ihren realen Anwendungskontexten, die nur Teilmengen Ihrer Entitäten enthalten, muss der Datenbankinitialisierer auf null gesetzt sein.
Es gibt andere Probleme, die bei der Verwendung mehrerer Kontexttypen auftreten - z. B. gemeinsam genutzte Entitätstypen und deren Übergabe von einem Kontext an einen anderen usw. Im Allgemeinen ist es möglich, dass Ihr Design viel sauberer wird und verschiedene Funktionsbereiche voneinander getrennt werden, aber es hat seine eigenen Kosten in zusätzlicher Komplexität.
quelle
Enable-Migrations -ContextTypeName MyContext -MigrationsDirectory Migrations\MyContextMigrations
jetzt funktioniert.Ich habe diese Antwort vor ungefähr vier Jahren geschrieben und meine Meinung hat sich nicht geändert. Seitdem gab es jedoch bedeutende Entwicklungen im Bereich der Mikrodienste. Ich habe am Ende spezifische Hinweise zu Mikrodiensten hinzugefügt ...
Ich werde gegen die Idee abwägen, mit realer Erfahrung, um meine Stimme zu stützen.
Ich wurde zu einer großen Anwendung weitergeleitet, die fünf Kontexte für eine einzelne Datenbank hatte. Am Ende haben wir alle Kontexte bis auf einen entfernt und sind zu einem einzigen Kontext zurückgekehrt.
Auf den ersten Blick scheint die Idee mehrerer Kontexte eine gute Idee zu sein. Wir können unseren Datenzugriff in Domänen unterteilen und mehrere saubere, leichtgewichtige Kontexte bereitstellen. Klingt nach DDD, oder? Dies würde unseren Datenzugriff vereinfachen. Ein weiteres Argument für die Leistung ist, dass wir nur auf den Kontext zugreifen, den wir benötigen.
In der Praxis teilten viele unserer Tabellen mit dem Anwachsen unserer Anwendung Beziehungen in unseren verschiedenen Kontexten. Beispielsweise erforderten Abfragen an Tabelle A in Kontext 1 auch das Verknüpfen von Tabelle B in Kontext 2.
Dies ließ uns ein paar schlechte Entscheidungen. Wir könnten die Tabellen in den verschiedenen Kontexten duplizieren. Wir haben es versucht. Dies führte zu mehreren Zuordnungsproblemen, einschließlich einer EF-Einschränkung, bei der jede Entität einen eindeutigen Namen haben muss. So kamen wir zu Entitäten mit den Namen Person1 und Person2 in den verschiedenen Kontexten. Man könnte argumentieren, dass dies unsererseits schlechtes Design war, aber trotz unserer besten Bemühungen ist unsere Anwendung auf diese Weise tatsächlich in der realen Welt gewachsen.
Wir haben auch versucht, beide Kontexte abzufragen, um die benötigten Daten zu erhalten. Zum Beispiel würde unsere Geschäftslogik die Hälfte dessen, was sie benötigt, aus Kontext 1 und die andere Hälfte aus Kontext 2 abfragen. Dies hatte einige Hauptprobleme. Anstatt eine Abfrage für einen einzelnen Kontext durchzuführen, mussten mehrere Abfragen in verschiedenen Kontexten durchgeführt werden. Dies hat eine echte Leistungsstrafe.
Am Ende ist die gute Nachricht, dass es einfach war, die verschiedenen Kontexte zu entfernen. Der Kontext soll ein leichtes Objekt sein. Daher denke ich nicht, dass Leistung ein gutes Argument für mehrere Kontexte ist. In fast allen Fällen glaube ich, dass ein einzelner Kontext einfacher, weniger komplex und wahrscheinlich leistungsfähiger ist, und Sie müssen keine Reihe von Workarounds implementieren, um ihn zum Laufen zu bringen.
Ich dachte an eine Situation, in der mehrere Kontexte nützlich sein könnten. Ein separater Kontext kann verwendet werden, um ein physisches Problem mit der Datenbank zu beheben, in der sie tatsächlich mehr als eine Domäne enthält. Im Idealfall wäre ein Kontext eins zu eins zu einer Domäne, der eins zu eins zu einer Datenbank wäre. Mit anderen Worten, wenn eine Reihe von Tabellen in keiner Weise mit den anderen Tabellen in einer bestimmten Datenbank verwandt ist, sollten sie wahrscheinlich in eine separate Datenbank gezogen werden. Mir ist klar, dass dies nicht immer praktisch ist. Aber wenn eine Reihe von Tabellen so unterschiedlich ist, dass Sie sie gerne in eine separate Datenbank aufteilen würden (aber Sie möchten dies nicht tun), könnte ich den Fall für die Verwendung eines separaten Kontexts sehen, aber nur, weil es tatsächlich zwei separate Domänen gibt.
In Bezug auf Mikrodienste ist ein einziger Kontext immer noch sinnvoll. Für Mikrodienste hätte jedoch jeder Dienst seinen eigenen Kontext, der nur die für diesen Dienst relevanten Datenbanktabellen enthält. Mit anderen Worten, wenn Dienst x auf die Tabellen 1 und 2 zugreift und Dienst y auf die Tabellen 3 und 4 zugreift, hat jeder Dienst seinen eigenen eindeutigen Kontext, der für diesen Dienst spezifische Tabellen enthält.
Ich interessiere mich für deine Gedanken.
quelle
Dieser Thread ist gerade auf StackOverflow aufgetaucht und deshalb wollte ich eine weitere "B) Zusicherung geben, dass dies alles in Ordnung sein wird" :)
Ich mache genau das über das DDD Bounded Context-Muster. Ich habe darüber in meinem Buch Programming Entity Framework: DbContext geschrieben und es steht im Mittelpunkt eines 50-minütigen Moduls in einem meiner Kurse zu Pluralsight -> http://pluralsight.com/training/Courses/TableOfContents/efarchitecture
quelle
Unterscheiden von Kontexten durch Festlegen des Standardschemas
In EF6 können Sie mehrere Kontexte haben. Geben Sie einfach den Namen für das Standarddatenbankschema in der
OnModelCreating
Methode IhrerDbContext
abgeleiteten Klasse an (wo sich die Fluent-API-Konfiguration befindet). Dies funktioniert in EF6:In diesem Beispiel wird "Kunde" als Präfix für Ihre Datenbanktabellen verwendet (anstelle von "dbo"). Noch wichtiger ist, dass auch die
__MigrationHistory
Tabelle (n) vorangestellt wird , zCustomer.__MigrationHistory
. Sie können also mehr als eine__MigrationHistory
Tabelle in einer einzelnen Datenbank haben, eine für jeden Kontext. Die Änderungen, die Sie für einen Kontext vornehmen, wirken sich also nicht auf den anderen aus.Geben Sie beim Hinzufügen der Migration den vollständig qualifizierten Namen Ihrer Konfigurationsklasse (abgeleitet von
DbMigrationsConfiguration
) als Parameter imadd-migration
Befehl an:Ein kurzes Wort zum Kontextschlüssel
Laut diesem MSDN-Artikel " Kapitel - Mehrere Modelle, die auf dieselbe Datenbank abzielen " würde EF 6 die Situation wahrscheinlich auch dann behandeln, wenn nur eine
MigrationHistory
Tabelle vorhanden wäre, da in der Tabelle eine ContextKey- Spalte zur Unterscheidung der Migrationen vorhanden ist.Ich bevorzuge jedoch mehr als eine
MigrationHistory
Tabelle, indem ich das oben erläuterte Standardschema spezifiziere.Verwenden separater Migrationsordner
In einem solchen Szenario möchten Sie möglicherweise auch mit verschiedenen "Migrations" -Ordnern in Ihrem Projekt arbeiten. Sie können Ihre
DbMigrationsConfiguration
abgeleitete Klasse mithilfe derMigrationsDirectory
Eigenschaft entsprechend einrichten :Zusammenfassung
Alles in allem kann man sagen, dass alles sauber getrennt ist: Kontexte, Migrationsordner im Projekt und Tabellen in der Datenbank.
Ich würde eine solche Lösung wählen, wenn es Gruppen von Entitäten gibt, die Teil eines größeren Themas sind, aber nicht (über Fremdschlüssel) miteinander verbunden sind.
Wenn die Gruppen von Entitäten nichts miteinander zu tun haben, würde ich für jede von ihnen eine separate Datenbank erstellen und auch in verschiedenen Projekten darauf zugreifen, wahrscheinlich mit einem einzigen Kontext in jedem Projekt.
quelle
Einfaches Beispiel, um Folgendes zu erreichen:
Bereich einfach die Eigenschaften im Hauptkontext: (wird zum Erstellen und Verwalten der Datenbank verwendet) Hinweis: Verwenden Sie einfach protected: (Entität ist hier nicht verfügbar)
MonitorContext: Stellen Sie hier eine separate Entität bereit
Diagnosemodell:
Wenn Sie möchten, können Sie alle Entitäten im Haupt-ApplicationDbContext als geschützt markieren. Erstellen Sie dann nach Bedarf zusätzliche Kontexte für jede Trennung von Schemas.
Sie alle verwenden dieselbe Verbindungszeichenfolge, verwenden jedoch separate Verbindungen. Überkreuzen Sie also keine Transaktionen und achten Sie auf Sperrprobleme. Im Allgemeinen ist Ihre Design-Trennung so, dass dies sowieso nicht passieren sollte.
quelle
DbSet<x>
Definition hinzu. Ich mache das in einer Teilklasse, die dem entspricht, was der EF Designer macht.Erinnerung: Wenn Sie mehrere Kontexte kombinieren, stellen Sie sicher, dass Sie alle Funktionen in Ihren verschiedenen Kontexten ausschneiden und
RealContexts.OnModelCreating()
in Ihre einzelne einfügenCombinedContext.OnModelCreating()
.Ich habe nur Zeit damit verschwendet, herauszufinden, warum meine Kaskaden-Löschbeziehungen nicht beibehalten wurden, nur um festzustellen, dass ich den
modelBuilder.Entity<T>()....WillCascadeOnDelete();
Code nicht aus meinem realen Kontext in meinen kombinierten Kontext portiert hatte .quelle
OtherContext.OnModelCreating()
aus Ihrem kombinierten Kontext aufrufen ?Mein Bauch sagte mir dasselbe, als ich auf dieses Design stieß.
Ich arbeite an einer Codebasis, in der eine Datenbank drei dbContexts enthält. 2 der 3 Datenbankkontexte sind abhängig von Informationen aus 1 Datenbankkontext, da sie die Verwaltungsdaten bereitstellen. Dieses Design hat Einschränkungen auferlegt, wie Sie Ihre Daten abfragen können. Ich bin auf dieses Problem gestoßen, bei dem Sie nicht über Datenbankkontexte hinweg beitreten können. Stattdessen müssen Sie die beiden separaten Datenbankkontexte abfragen und dann einen Join im Speicher durchführen oder beide durchlaufen, um die Kombination der beiden als Ergebnismenge zu erhalten. Das Problem dabei ist, dass Sie nicht nach einer bestimmten Ergebnismenge abfragen, sondern jetzt alle Ihre Datensätze in den Speicher laden und dann einen Join für die beiden Ergebnismengen im Speicher durchführen. Es kann die Dinge wirklich verlangsamen.
Ich würde die Frage stellen "Nur weil du kannst, solltest du?"In
diesem Artikel finden Sie das Problem, das bei diesem Entwurf aufgetreten ist . Der angegebene LINQ-Ausdruck enthält Verweise auf Abfragen, die verschiedenen Kontexten zugeordnet sind
quelle
Inspiriert von [@JulieLermans DDD MSDN Mag Article 2013] [1]
quelle
Im Code zuerst können Sie mehrere DBContext und nur eine Datenbank haben. Sie müssen nur die Verbindungszeichenfolge im Konstruktor angeben.
quelle
Noch ein bisschen "Weisheit". Ich habe eine Datenbank mit Blick auf das Internet und eine interne App. Ich habe einen Kontext für jedes Gesicht. Das hilft mir, eine disziplinierte, sichere Trennung aufrechtzuerhalten.
quelle
Ich möchte einen Fall teilen, in dem die Möglichkeit, mehrere DBContexts in derselben Datenbank zu haben, meiner Meinung nach sinnvoll ist.
Ich habe eine Lösung mit zwei Datenbanken. Eine ist für Domänendaten außer Benutzerinformationen. Die andere dient ausschließlich der Benutzerinformation. Diese Aufteilung wird hauptsächlich durch die EU -Datenschutzgrundverordnung bestimmt . Durch zwei Datenbanken kann ich die Domänendaten frei verschieben (z. B. von Azure in meine Entwicklungsumgebung), solange sich die Benutzerdaten an einem sicheren Ort befinden.
Jetzt habe ich für die Benutzerdatenbank zwei Schemas über EF implementiert. Eine ist die Standardeinstellung, die vom AspNet Identity-Framework bereitgestellt wird. Das andere ist unsere eigene Implementierung von allem, was mit dem Benutzer zu tun hat. Ich bevorzuge diese Lösung gegenüber der Erweiterung des ApsNet-Schemas, da ich zukünftige Änderungen an der AspNet-Identität problemlos verarbeiten kann und gleichzeitig den Programmierern durch die Trennung klar wird, dass "unsere eigenen Benutzerinformationen" in dem von uns definierten spezifischen Benutzerschema enthalten sind .
quelle
Huh, ich habe ziemlich viel Zeit mit einem Problem mit separaten DB-Kontexten für jedes DB-Schema verbracht und hoffe, dass es jemand anderem hilft ...
Ich habe kürzlich begonnen, an einem Projekt zu arbeiten, das eine Datenbank mit 3 Schemas (DB First Approach) hatte, eines davon für die Benutzerverwaltung. Es gab ein DB-Kontextgerüst aus jedem einzelnen Schema. Natürlich waren Benutzer auch mit anderen Schemata verwandt, z. Schema KB hatte ein Tabellenthema, das "erstellt von", "zuletzt geändert von" usw. FK zum Identitätsschema, Tabellenbenutzer.
Diese Objekte wurden separat in C # geladen. Zuerst wurde das Thema aus einem Kontext geladen, dann wurden die Benutzer über Benutzer-IDs aus dem anderen Datenbankkontext geladen - nicht schön, müssen dies beheben! (Ähnlich wie bei der Verwendung mehrerer Datenbankkontexte in derselben Datenbank mit EF 6 )
Zuerst habe ich versucht, fehlende FK-Anweisungen aus dem Identitätsschema zum KB-Schema und zum EF modelBuilder im KB DB-Kontext hinzuzufügen. Das gleiche, als gäbe es nur einen Kontext, aber ich habe ihn in zwei getrennt.
Es hat nicht funktioniert, da kb db context keine Informationen über das Benutzerobjekt hatte, hat postgres einen Fehler zurückgegeben
relation "AppUsers" does not exist
. Die Select-Anweisung hatte keine richtigen Informationen zu Schema, Feldnamen usw.Ich hätte fast aufgegeben, aber dann bemerkte ich beim Laufen einen Schalter "-d"
dotnet ef dbcontext scaffold
. Die Abkürzung für -data-annotations - Verwenden Sie Attribute, um das Modell zu konfigurieren (sofern möglich). Wenn nicht angegeben, wird nur die fließende API verwendet. Mit diesem Schalter wurden Objekteigenschaften nicht im Datenbankkontext definiertOnModelCreating()
, sondern auf dem Objekt selbst mit Attributen.Auf diese Weise erhielt EF ausreichende Informationen zum Generieren einer richtigen SQL-Anweisung mit richtigen Feldnamen und Schemas.
TL; DR: Separate DB-Kontexte verarbeiten Beziehungen (FKs) zwischen ihnen nicht gut. Jeder Kontext enthält nur Informationen zu seinen eigenen Entitäten. Wenn Sie "-data-annotations" angeben
dotnet ef dbcontext scaffold
, werden diese Informationen nicht in jedem separaten Kontext, sondern in DB-Objekten selbst gespeichert.quelle