Ist es in Ordnung, ein Entity Framework DataContext-Objekt zu erstellen und es in jeder meiner CRUD-Methoden in einem using-Block zu entsorgen?

10

Ich erstelle eine wpf-Anwendung, die die folgenden Funktionen implementiert:

  1. Nehmen Sie Benutzereingaben und lesen Sie Daten aus Datenbanken
  2. Führen Sie einige Berechnungen durch
  3. Präsentieren Sie es dem Benutzer in mehreren Arten von Ansichten und schreiben Sie Änderungen zurück in db

Vorgeschlagene Architektur: Datenbank -> Entity Framework -> Repository -> Geschäftslogik -> Datendienst -> ViewModel

Gründe für die Verwendung dieser Architektur: Mehrere in der Anwendung vorhandene Szenarien (mehrere Ansichten) und mehrere Datenbanken. Daher bin ich bereit, das Repository in der Mitte für die Abstraktion zu verwenden.

Eine Einschränkung ist, dass der Kontext langlebig ist, wenn das Repository implementiert wird. Um dies zu überwinden, ist es in Ordnung, in jeder der Rohmethoden einen Kontext zu erstellen und diese in einem using () -Block zu entsorgen.

Sie können gerne alternative Ansätze vorschlagen.

Skyuppercut
quelle
Schauen Sie sich diesen Thread an, der Ihrer Anfrage ähnelt. stackoverflow.com/questions/21875816/…
Gopinath

Antworten:

16

Verwenden Sie ein DbContext-Objekt pro Datenzugriff oder Transaktion.

DbContextist ein leichtes Objekt; Es kann einmal pro Geschäftsvorfall verwendet werden. Wenn Sie DbContexteinen Singleton erstellen und in der gesamten Anwendung wiederverwenden, kann dies zu anderen Problemen führen, z. B. zu Problemen mit Parallelität und Speicherverlust.

DbContextimplementiert im Wesentlichen eine Arbeitseinheit. Behandle es entsprechend.

Entsorgen Sie keine DbContext-Objekte.

Obwohl die DbContextGeräte IDisposable, sollten Sie sie nicht manuell entsorgen oder in eine usingAnweisung einschließen. DbContextverwaltet sein eigenes Leben; Wenn Ihre Datenzugriffsanforderung abgeschlossen ist, DbContextwird die Datenbankverbindung automatisch für Sie geschlossen.

Um zu verstehen, warum dies der Fall ist, überlegen Sie, was passiert, wenn Sie eine Linq-Anweisung für eine Entitätssammlung von a ausführen DbContext. Wenn Sie einen Lazy-Laden Rückkehr IQueryableaus der Datenzugriffsmethode, stehen Sie eine Pipeline bis der , bis der Client nicht tatsächlich ausgeführt wird , einige Daten von ihm zwingt (durch den Aufruf FirstOrDefault(), ToList()oder über sie iterieren).

Weiterführende
Literatur Muss ich Dispose () für meine DbContext-Objekte immer aufrufen?
Warum sollten Sie nicht Singleton Datacontexts in Entity Framework verwenden ,
Rückkehr IEnumerable<T>gegen IQueryable<T>
Rückkehr sollte Repositorys IQueryable?

Robert Harvey
quelle
4
Ich bin mir zwar sicher, dass jemand einen Ausnahmefall dafür finden wird, aber ich kann ehrlich gesagt keinen guten Anwendungsfall für die Rückgabe eines nicht materialisierten IQueryable aus Ihren Datenzugriffsklassen finden. Das gibt dem Anrufcode nur die Möglichkeit, auf Ihren Datenzugriff zuzugreifen (was wahrscheinlich nichts zu tun hat) und sich mit Dingen zu beschäftigen. Ist es wirklich so wichtig, sich Sorgen über die Verwendung von usingBlöcken zu machen ? Oder denke ich nur nicht an einen Fall, in dem die Verwendung eines IQueryable, wie Sie meinen, die Mühe wert wäre?
Becuzz
@Becuzz: Der DbContextist für die Verwaltung seiner eigenen Lebensdauer verantwortlich. Mein Vorschlag ist, es das tun zu lassen; es wird funktionieren, ob Sie IQueryableoder verwenden IEnumerable. Der offensichtlichste Anwendungsfall, den ich mir beim verzögerten Laden vorstellen kann, ist der, bei dem Sie ein ViewModel-Objekt mit einer zugehörigen Sammlung zurückgeben, die Sammlung jedoch nie (oder nur teilweise) verwendet wird. IQueryableSo können Sie die Kosten für das Abrufen nicht verwendeter Datensätze vermeiden.
Robert Harvey
3
Ich verstehe das alles, es ist nur so, dass ich verbrannt wurde, weil Leute überall IQueryables zurückgeben. Und dann fügte etwas weiter oben in der Kette einige Includes oder andere Dinge hinzu, die zu einer schrecklich schlechten Abfrage führten (aus Sicht der DB-Leistung). Und das war ein lustiger Fehler. Daher hatte ich Gelegenheit darüber nachzudenken, ob die Rückgabe eines IQueryable jemals eine gute Idee ist. Und ich konnte mir nie eine Zeit vorstellen, in der sich die Wartungsprobleme gelohnt hatten. (Forts.)
Becuzz
4
@RobertHarvey Was genau ist der Sinn einer Repository-Schicht, wenn sie eine IQueryable an den Client zurückgibt? Sie geben dem Client im Grunde die Möglichkeit, Abfragen zu schreiben - sicher, dass es sich nicht um SQL-Abfragen handelt, aber es handelt sich dennoch um Abfragen (nur mit C # geschrieben), die überall zu finden sind. Wenn ein Repository IQueryable zurückgibt, können Sie das Repository auch wegwerfen.
CodingYoshi
8
@RobertHarvey Ich bin nicht einverstanden, DbContext nicht zu entsorgen, und bin nicht einverstanden mit dem Artikel, auf den verwiesen wird. Die ganze Idee ist, gegen die Schnittstelle zu codieren, und die Schnittstelle sagt mir, dass es IDisposable ist. Ich werde meinen Code nicht basierend auf dem Innenleben schreiben, wie das EF-Team DbContext implementiert hat, oder die Entwickler in diesem Team verfolgen - sie können ihn jederzeit ändern. Ich werde mich selbst oder andere Entwickler auch nicht bitten, sich mit dem Innenleben jeder Klasse zu befassen, um zu sehen, ob IDisposable wirklich nützlich ist. Ich habe zu hart gearbeitet, um die Entwickler in meinem Team dazu zu bringen, sich zu entsorgen, nur um sie nicht immer zu fragen.
CodingYoshi
-3

Idealerweise sollte der Kontext für eine einzelne Transaktion initialisiert und beendet werden. In Ihrem Fall sollte der Kontext in Business Logic instanziiert und zum Lesen / Schreiben von Daten an das Repository weitergeleitet werden.

Gopinath
quelle
2
Ja, weil Geschäftslogik besser zu warten ist, wenn sie eng mit dem Datenzugriff verbunden ist ... :(
TheCatWhisperer
-3

Wenn Sie DbContext für jede Methode in Ihrer Anwendung aufrufen, tritt ein Speicherverlust auf. Verwenden Sie eine einzelne Instanz des DbContext. Siehe den Kommentar im folgenden Beispiel:

public bool IsInStock(int _ProductId)
{
  var result = false;

  try
  {
    using (var dataService = new StoreDbDataService()) // NB: This line on each method will eventually cause memory leak.
    {
      result = dataService.IsInStock(_ProductId);
    }
  }
  catch (Exception ex)
  {
    Log.LogException(ex);
  }

  return result;
}
Joseph Majase Sithole
quelle
1
Können Sie erklären, warum das Aufrufen von DbContext einen Speicherverlust verursachen würde? Der Kommentar in der Quelle hilft mir nicht, ihn zu verstehen. Ich würde annehmen, dass der using-Block dazu führen würde, dass Dispose im StoreDBDataService aufgerufen wird, wodurch schließlich alle zugewiesenen Ressourcen bereinigt werden, nicht wahr?
Kasper van den Berg
Dies ist im Grunde der Ron Swanson "Erlaubnis" -Clip, aber im Code.
Dagrooms