Ein DbContext pro Webanforderung… warum?

398

Ich habe viele Artikel gelesen, in denen erklärt wurde, wie Entity Frameworks DbContextso eingerichtet werden, dass nur eines pro HTTP-Webanforderung mit verschiedenen DI-Frameworks erstellt und verwendet wird.

Warum ist das überhaupt eine gute Idee? Welche Vorteile erzielen Sie mit diesem Ansatz? Gibt es bestimmte Situationen, in denen dies eine gute Idee wäre? Gibt es Dinge, die Sie mit dieser Technik tun können, die Sie nicht tun können, wenn Sie DbContexts pro Repository-Methodenaufruf instanziieren ?

Andrew
quelle
9
Gueddari in mehdi.me/ambient-dbcontext-in-ef6 ruft die DbContext-Instanz pro Repository-Methode auf und ruft ein Antimuster auf. Zitat: "Auf diese Weise verlieren Sie so gut wie alle Funktionen, die Entity Framework über den DbContext bereitstellt, einschließlich des Caches der ersten Ebene, der Identitätszuordnung, der Arbeitseinheit sowie der Funktionen zum Verfolgen von Änderungen und zum verzögerten Laden . " Hervorragender Artikel mit großartigen Vorschlägen für den Umgang mit dem Lebenszyklus von DBContexts. Auf jeden Fall lesenswert.
Christoph

Antworten:

565

ANMERKUNG: Diese Antwort bezieht sich auf das Entity Framework DbContext, ist jedoch auf jede Art von Unit of Work-Implementierung anwendbar, z. B. auf LINQ to SQL DataContextund NHibernate ISession.

Beginnen wir mit dem Echo von Ian: Eine einzige DbContextfür die gesamte Anwendung zu haben, ist eine schlechte Idee. Dies ist nur dann sinnvoll, wenn Sie über eine Single-Threaded-Anwendung und eine Datenbank verfügen, die ausschließlich von dieser einzelnen Anwendungsinstanz verwendet wird. Das DbContextist nicht threadsicher und da die DbContextDaten zwischengespeichert werden, wird es ziemlich bald veraltet. Dies bringt Sie in alle möglichen Schwierigkeiten, wenn mehrere Benutzer / Anwendungen gleichzeitig an dieser Datenbank arbeiten (was natürlich sehr häufig ist). Aber ich gehe davon aus, dass Sie das bereits wissen und nur wissen möchten, warum Sie nicht einfach DbContextjedem, der es braucht , eine neue Instanz (dh mit einem vorübergehenden Lebensstil) von injizieren . (Weitere Informationen darüber, warum eine einzelne DbContextoder sogar im Kontext pro Thread schlecht ist, finden Sie in dieser Antwort. )

Lassen Sie mich zunächst sagen, dass die Registrierung eines DbContextals vorübergehend funktionieren könnte, aber normalerweise möchten Sie eine einzelne Instanz einer solchen Arbeitseinheit in einem bestimmten Bereich haben. In einer Webanwendung kann es praktisch sein, einen solchen Bereich an den Grenzen einer Webanforderung zu definieren. somit ein Lebensstil pro Webanfrage. Auf diese Weise können Sie eine ganze Reihe von Objekten im selben Kontext arbeiten lassen. Mit anderen Worten, sie arbeiten innerhalb derselben Geschäftstransaktion.

Wenn Sie nicht das Ziel haben, dass eine Reihe von Operationen im selben Kontext ausgeführt werden, ist in diesem Fall der vorübergehende Lebensstil in Ordnung, aber es gibt einige Dinge zu beachten:

  • Da jedes Objekt eine eigene Instanz erhält, muss jede Klasse, die den Status des Systems _context.SaveChanges()ändert , aufrufen (andernfalls gehen Änderungen verloren). Dies kann Ihren Code komplizieren und dem Code eine zweite Verantwortung hinzufügen (die Verantwortung für die Kontrolle des Kontexts). Dies verstößt gegen das Prinzip der Einzelverantwortung .
  • Sie müssen sicherstellen, dass Entitäten [geladen und gespeichert von a DbContext] niemals den Gültigkeitsbereich einer solchen Klasse verlassen, da sie nicht in der Kontextinstanz einer anderen Klasse verwendet werden können. Dies kann Ihren Code enorm komplizieren, da Sie diese Entitäten, wenn Sie sie benötigen, erneut über die ID laden müssen, was ebenfalls zu Leistungsproblemen führen kann.
  • Seit der DbContextImplementierung IDisposablemöchten Sie wahrscheinlich immer noch alle erstellten Instanzen entsorgen. Wenn Sie dies tun möchten, haben Sie grundsätzlich zwei Möglichkeiten. Sie müssen sie direkt nach dem Aufruf auf dieselbe Weise entsorgen. context.SaveChanges()In diesem Fall übernimmt die Geschäftslogik jedoch den Besitz eines Objekts, das von außen weitergegeben wird. Die zweite Option besteht darin, alle erstellten Instanzen an der Grenze der HTTP-Anforderung zu entsorgen. In diesem Fall benötigen Sie jedoch noch einen Bereich, um den Container darüber zu informieren, wann diese Instanzen entsorgt werden müssen.

Eine andere Möglichkeit ist, überhaupt keine zu injizieren DbContext. Stattdessen fügen Sie eine ein DbContextFactory, die eine neue Instanz erstellen kann (ich habe diesen Ansatz in der Vergangenheit verwendet). Auf diese Weise steuert die Geschäftslogik den Kontext explizit. Wenn es so aussehen könnte:

public void SomeOperation()
{
    using (var context = this.contextFactory.CreateNew())
    {
        var entities = this.otherDependency.Operate(
            context, "some value");

        context.Entities.InsertOnSubmit(entities);

        context.SaveChanges();
    }
}

Das Plus daran ist, dass Sie das Leben der DbContextexplizit verwalten und es einfach einzurichten ist. Außerdem können Sie einen einzelnen Kontext in einem bestimmten Bereich verwenden, was klare Vorteile bietet, z. B. das Ausführen von Code in einem einzelnen Geschäftsvorgang und das Weitergeben von Entitäten, da diese von demselben stammen DbContext.

Der Nachteil ist, dass Sie die DbContextMethode von Methode zu Methode weitergeben müssen (was als Methodeninjektion bezeichnet wird). Beachten Sie, dass diese Lösung in gewissem Sinne mit dem "Scoped" -Ansatz identisch ist, der Umfang jedoch jetzt im Anwendungscode selbst gesteuert wird (und möglicherweise viele Male wiederholt wird). Es ist die Anwendung, die für die Erstellung und Entsorgung der Arbeitseinheit verantwortlich ist. Da das DbContexterstellt wird, nachdem das Abhängigkeitsdiagramm erstellt wurde, ist die Konstruktorinjektion nicht im Bild und Sie müssen auf die Methodeninjektion zurückgreifen, wenn Sie den Kontext von einer Klasse zur anderen weitergeben müssen.

Die Methodeninjektion ist nicht so schlecht, aber wenn die Geschäftslogik komplexer wird und mehr Klassen involviert sind, müssen Sie sie von Methode zu Methode und von Klasse zu Klasse übergeben, was den Code sehr komplizieren kann (wie ich gesehen habe) dies in der Vergangenheit). Für eine einfache Anwendung ist dieser Ansatz jedoch ausreichend.

Aufgrund der Nachteile, die dieser Factory-Ansatz für größere Systeme hat, kann ein anderer Ansatz nützlich sein, bei dem Sie den Container oder den Infrastrukturcode / Composition Root die Arbeitseinheit verwalten lassen. Dies ist der Stil, um den es in Ihrer Frage geht.

Indem Sie den Container und / oder die Infrastruktur damit umgehen lassen, wird Ihr Anwendungscode nicht durch das Erstellen, (optional) Festschreiben und Entsorgen einer UoW-Instanz verschmutzt, wodurch die Geschäftslogik einfach und sauber bleibt (nur eine einzige Verantwortung). Bei diesem Ansatz gibt es einige Schwierigkeiten. Haben Sie beispielsweise die Instanz festgeschrieben und entsorgt?

Die Entsorgung einer Arbeitseinheit kann am Ende der Webanforderung erfolgen. Viele Menschen gehen jedoch fälschlicherweise davon aus, dass dies auch der Ort ist, an dem die Arbeitseinheit festgelegt wird. Zu diesem Zeitpunkt in der Anwendung können Sie jedoch einfach nicht sicher bestimmen, ob die Arbeitseinheit tatsächlich festgeschrieben werden soll. Beispiel: Wenn der Business-Layer-Code eine Ausnahme ausgelöst hat, die höher im Callstack abgefangen wurde, möchten Sie definitiv kein Commit durchführen.

Die eigentliche Lösung besteht wiederum darin, einen Bereich explizit zu verwalten, diesmal jedoch im Composition Root. Wenn Sie die gesamte Geschäftslogik hinter dem Befehls- / Handler-Muster abstrahieren , können Sie einen Dekorator schreiben, der um jeden Befehlshandler gewickelt werden kann, der dies ermöglicht. Beispiel:

class TransactionalCommandHandlerDecorator<TCommand>
    : ICommandHandler<TCommand>
{
    readonly DbContext context;
    readonly ICommandHandler<TCommand> decorated;

    public TransactionCommandHandlerDecorator(
        DbContext context,
        ICommandHandler<TCommand> decorated)
    {
        this.context = context;
        this.decorated = decorated;
    }

    public void Handle(TCommand command)
    {
        this.decorated.Handle(command);

        context.SaveChanges();
    } 
}

Dadurch wird sichergestellt, dass Sie diesen Infrastrukturcode nur einmal schreiben müssen. Mit jedem festen DI-Container können Sie einen solchen Dekorator so konfigurieren, dass er alle ICommandHandler<T>Implementierungen auf konsistente Weise umschließt.

Steven
quelle
2
Wow - danke für die gründliche Antwort. Wenn ich zweimal abstimmen könnte, würde ich. Oben sagen Sie "... keine Absicht, eine ganze Reihe von Operationen im selben Kontext ablaufen zu lassen, in diesem Fall ist der vorübergehende Lebensstil in Ordnung ...". Was meinst du konkret mit "vorübergehend"?
Andrew
14
@ Andrew: 'Transient' ist ein Abhängigkeitsinjektionskonzept. Wenn ein Dienst als transient konfiguriert ist, wird jedes Mal, wenn er in einen Consumer injiziert wird, eine neue Instanz des Dienstes erstellt.
Steven
1
@ user981375: Für CRUD-Operationen können Sie ein generisches CreateCommand<TEnity>und ein generisches erstellen CreateCommandHandler<TEntity> : ICommandHandler<CreateCommand<TEntity>>(und dasselbe für Aktualisieren und Löschen tun und hatten eine einzige GetByIdQuery<TEntity>Abfrage). Sie sollten sich jedoch fragen, ob dieses Modell eine nützliche Abstraktion für CRUD-Operationen ist oder nur die Komplexität erhöht. Dennoch können Sie von der Möglichkeit profitieren, mit diesem Modell auf einfache Weise Querschnittsthemen (durch Dekorateure) hinzuzufügen. Sie müssen die Vor- und Nachteile abwägen.
Steven
3
+1 Würden Sie glauben, dass ich all diese Antworten geschrieben habe, bevor ich sie tatsächlich gelesen habe? Übrigens IMO Ich denke, es ist wichtig für Sie, die Entsorgung des DbContext am Ende zu diskutieren (obwohl es großartig ist, dass Sie Container-Agnostiker bleiben)
Ruben Bartelink
1
Aber Sie geben den Kontext nicht an die dekorierte Klasse weiter. Wie könnte die dekorierte Klasse mit demselben Kontext arbeiten, der an die übergeben wurde TransactionCommandHandlerDecorator? Wenn die dekorierte Klasse beispielsweise eine InsertCommandHandlerKlasse ist, wie kann sie dann die Einfügeoperation im Kontext registrieren (DbContext in EF)?
Masoud
35

Es gibt zwei widersprüchliche Empfehlungen von Microsoft, und viele Menschen verwenden DbContexts auf völlig unterschiedliche Weise.

  1. Eine Empfehlung ist, "DbContexts so schnell wie möglich zu entsorgen", da ein lebendiger DbContext wertvolle Ressourcen wie Datenbankverbindungen usw. beansprucht.
  2. Die andere besagt, dass ein DbContext pro Anfrage dringend empfohlen wird

Diese widersprechen sich, denn wenn Ihre Anfrage viel mit dem Db-Zeug zu tun hat, wird Ihr DbContext ohne Grund beibehalten. Daher ist es eine Verschwendung, Ihren DbContext am Leben zu erhalten, während Ihre Anfrage nur darauf wartet, dass zufällige Dinge erledigt werden ...

So viele Leute, die Regel 1 folgen, haben ihre DbContexts in ihrem "Repository-Muster" und erstellen eine neue Instanz pro Datenbankabfrage, also X * DbContext pro Anfrage

Sie erhalten nur ihre Daten und entsorgen den Kontext so schnell wie möglich. Dies wird von vielen Menschen als akzeptable Praxis angesehen. Dies hat zwar den Vorteil , dass Sie Ihre Datenbankressourcen für die minimale Zeit belegen, aber es opfert eindeutig alle UnitOfWork- und Caching- Süßigkeiten, die EF zu bieten hat.

Wenn Sie eine einzelne Mehrzweckinstanz von DbContext am Leben erhalten, werden die Vorteile von Caching maximiert. Da DbContext jedoch nicht threadsicher ist und jede Webanforderung in einem eigenen Thread ausgeführt wird, ist ein DbContext pro Anforderung die längste, die Sie behalten können.

Die Empfehlung des EF-Teams zur Verwendung von 1-dB-Kontext pro Anforderung basiert eindeutig auf der Tatsache, dass sich eine UnitOfWork in einer Webanwendung höchstwahrscheinlich innerhalb einer Anforderung befindet und diese Anforderung einen Thread hat. Ein DbContext pro Anfrage ist also der ideale Vorteil von UnitOfWork und Caching.

Aber in vielen Fällen ist dies nicht wahr. Ich halte Protokollierung über einen separaten UnitOfWork damit einen neuen DbContext für in Post-Request Logging mit Asynchron - Gewinde ist völlig akzeptabel

Schließlich stellt sich heraus, dass die Lebensdauer eines DbContext auf diese beiden Parameter beschränkt ist. UnitOfWork und Thread

Anestis Kivranoglou
quelle
3
Um ehrlich zu sein, sollten Ihre HTTP-Anfragen ziemlich schnell fertig sein (wenige ms). Wenn sie länger dauern, sollten Sie über eine Hintergrundverarbeitung mit einem externen Job Scheduler nachdenken, damit die Anforderung sofort zurückgegeben werden kann. Allerdings sollte Ihre Architektur auch nicht wirklich auf HTTP basieren. Insgesamt eine gute Antwort.
Crush
34

Keine einzige Antwort hier beantwortet tatsächlich die Frage. Das OP fragte nicht nach einem DbContext-Design für Singleton / pro Anwendung, sondern nach einem Design pro (Web-) Anfrage und nach möglichen Vorteilen.

Ich verweise auf http://mehdi.me/ambient-dbcontext-in-ef6/, da Mehdi eine fantastische Ressource ist:

Mögliche Leistungssteigerungen.

Jede DbContext-Instanz verwaltet einen Cache der ersten Ebene aller Entitäten, die aus der Datenbank geladen werden. Wenn Sie eine Entität anhand ihres Primärschlüssels abfragen, versucht der DbContext zunächst, sie aus dem Cache der ersten Ebene abzurufen, bevor sie standardmäßig aus der Datenbank abgefragt wird. Abhängig von Ihrem Datenabfragemuster kann die Wiederverwendung desselben DbContext über mehrere aufeinanderfolgende Geschäftstransaktionen hinweg dazu führen, dass dank des DbContext-Caches der ersten Ebene weniger Datenbankabfragen durchgeführt werden.

Es ermöglicht das verzögerte Laden.

Wenn Ihre Dienste persistente Entitäten zurückgeben (im Gegensatz zur Rückgabe von Ansichtsmodellen oder anderen Arten von DTOs) und Sie das verzögerte Laden dieser Entitäten nutzen möchten, muss die Lebensdauer der DbContext-Instanz, von der diese Entitäten abgerufen wurden, darüber hinausgehen den Umfang des Geschäftsvorfalls. Wenn die Dienstmethode die vor der Rückgabe verwendete DbContext-Instanz entsorgt, schlägt jeder Versuch fehl, Eigenschaften für die zurückgegebenen Entitäten verzögert zu laden (ob die Verwendung von verzögertem Laden eine gute Idee ist oder nicht, ist eine andere Debatte, auf die wir nicht näher eingehen werden Hier). In unserem Webanwendungsbeispiel wird das verzögerte Laden normalerweise in Controller-Aktionsmethoden für Entitäten verwendet, die von einer separaten Serviceschicht zurückgegeben werden. In diesem Fall,

Denken Sie daran, dass es auch Nachteile gibt. Dieser Link enthält viele andere Ressourcen, die Sie zu diesem Thema lesen können.

Posten Sie dies einfach, falls jemand anderes auf diese Frage stößt und sich nicht in Antworten vertieft, die die Frage nicht wirklich beantworten.

user4893106
quelle
Guter Link! Die explizite Verwaltung des DBContext scheint der sicherste Ansatz zu sein.
Aggsol
22

Ich bin mir ziemlich sicher, dass der DbContext überhaupt nicht threadsicher ist. Das Ding zu teilen ist also nie eine gute Idee.

Ian
quelle
Meinst du, es ist nie eine gute Idee, es über HTTP-Anfragen zu teilen?
Andrew
2
Ja Andrew, das hat er gemeint. Das Teilen des Kontexts gilt nur für Single-Thread-Desktop-Apps.
Elisabeth
10
Was ist mit dem Teilen des Kontexts für eine Anfrage? Für eine Anfrage können wir also auf verschiedene Repositorys zugreifen und eine Transaktion über diese hinweg durchführen, indem wir ein und denselben Kontext gemeinsam nutzen.
Lyubomir Velchev
16

Eine Sache, die in der Frage oder Diskussion nicht wirklich angesprochen wird, ist die Tatsache, dass DbContext Änderungen nicht abbrechen kann. Sie können Änderungen einreichen, aber Sie können den Änderungsbaum nicht löschen. Wenn Sie also einen Kontext pro Anforderung verwenden, haben Sie kein Glück, wenn Sie Änderungen aus irgendeinem Grund wegwerfen müssen.

Persönlich erstelle ich bei Bedarf Instanzen von DbContext - normalerweise angehängt an Geschäftskomponenten, die den Kontext bei Bedarf neu erstellen können. Auf diese Weise habe ich die Kontrolle über den Prozess, anstatt mir eine einzelne Instanz aufzwingen zu lassen. Ich muss den DbContext auch nicht bei jedem Controller-Start erstellen, unabhängig davon, ob er tatsächlich verwendet wird. Wenn ich dann immer noch Instanzen pro Anforderung haben möchte, kann ich sie im CTOR erstellen (über DI oder manuell) oder sie nach Bedarf in jeder Controller-Methode erstellen. Persönlich verfolge ich normalerweise den letzteren Ansatz, um zu vermeiden, dass DbContext-Instanzen erstellt werden, wenn sie nicht wirklich benötigt werden.

Es hängt davon ab, aus welchem ​​Blickwinkel Sie es auch betrachten. Für mich hat die Instanz pro Anfrage nie Sinn gemacht. Gehört der DbContext wirklich zur HTTP-Anfrage? In Bezug auf das Verhalten ist das der falsche Ort. Ihre Geschäftskomponenten sollten Ihren Kontext erstellen, nicht die HTTP-Anforderung. Dann können Sie Ihre Geschäftskomponenten nach Bedarf erstellen oder wegwerfen und müssen sich nie um die Lebensdauer des Kontexts sorgen.

Rick Strahl
quelle
1
Dies ist eine interessante Antwort und ich stimme Ihnen teilweise zu. Für mich muss ein DbContext nicht an eine Webanforderung gebunden sein, sondern wird immer an eine einzelne 'Anfrage' wie in 'Geschäftstransaktion' geschrieben. Und wenn Sie den Kontext mit einem Geschäftsvorgang verknüpfen, wird die Stornierung von Änderungen sehr seltsam. Wenn Sie es jedoch nicht an der Webanforderungsgrenze haben, bedeutet dies nicht, dass die Geschäftskomponenten (BCs) den Kontext erstellen sollten. Ich denke, das liegt nicht in ihrer Verantwortung. Stattdessen können Sie das Scoping mithilfe von Dekoratoren um Ihre BCs anwenden. Auf diese Weise können Sie den Gültigkeitsbereich sogar ohne Codeänderung ändern.
Steven
1
In diesem Fall sollte sich die Injektion in das Geschäftsobjekt mit dem Lebensdauermanagement befassen. Meiner Ansicht nach besitzt das Geschäftsobjekt den Kontext und sollte als solches die Lebensdauer steuern.
Rick Strahl
Kurz gesagt, was meinen Sie mit "die Fähigkeit, den Kontext bei Bedarf neu zu erstellen"? Wirfst du deine eigene Rollback-Fähigkeit? Können Sie ein bisschen näher darauf eingehen?
tntwyckoff
2
Persönlich finde ich es etwas mühsam, dort zu Beginn einen DbContext zu erzwingen. Es gibt keine Garantie dafür, dass Sie überhaupt auf die Datenbank zugreifen müssen. Möglicherweise rufen Sie einen Drittanbieter an, der auf dieser Seite den Status ändert. Oder vielleicht haben Sie tatsächlich 2 oder 3 Datenbanken, mit denen Sie gleichzeitig arbeiten. Sie würden zu Beginn keine DbContexts erstellen, nur für den Fall, dass Sie sie verwenden. Das Unternehmen kennt die Daten, mit denen es arbeitet, also gehört es dazu. Setzen Sie einfach ein TransactionScope an den Start, wenn es benötigt wird. Ich glaube nicht, dass alle Anrufe einen brauchen. Es braucht Ressourcen.
Daniel Lorenz
Das ist die Frage, ob Sie dem Container erlauben, die Lebensdauer des Datenbankkontexts zu steuern, der dann die Lebensdauer der übergeordneten Steuerelemente manchmal übermäßig steuert. Angenommen, ich möchte einen einfachen Service-Singleton in meine Controller einspeisen, dann kann ich aufgrund der Semantik pro Anforderung keine Konstruktorinjektion verwenden.
Davidcarr
10

Ich stimme früheren Meinungen zu. Es ist gut zu sagen, dass Sie mehr Speicher benötigen, wenn Sie DbContext in einer Single-Thread-App freigeben möchten. Zum Beispiel benötigt meine Webanwendung in Azure (eine extra kleine Instanz) weitere 150 MB Speicher und ich habe ungefähr 30 Benutzer pro Stunde. Anwendungsfreigabe von DBContext in HTTP-Anforderung

Hier ist ein echtes Beispielbild: Die Anwendung wurde um 12:00 Uhr bereitgestellt

Miroslav Holec
quelle
Möglicherweise besteht die Idee darin, den Kontext für eine Anfrage zu teilen. Wenn wir auf verschiedene Repositorys und - DBSet-Klassen zugreifen und möchten, dass die Operationen mit ihnen transaktional sind, sollte dies eine gute Lösung sein. Schauen Sie sich das Open-Source-Projekt mvcforum.com an. Ich denke, das geschieht bei der Implementierung des Entwurfsmusters von Unit Of Work.
Lyubomir Velchev
3

Was ich daran mag, ist, dass es die Arbeitseinheit (wie der Benutzer es sieht - dh eine Seite einreichen) mit der Arbeitseinheit im ORM-Sinne ausrichtet.

Daher können Sie die gesamte Seitenübermittlung transaktional durchführen, was Sie nicht tun könnten, wenn Sie CRUD-Methoden bei jeder Erstellung eines neuen Kontexts verfügbar machen würden.

RB.
quelle
3

Ein weiterer untertriebener Grund dafür, dass kein Singleton-DbContext verwendet wird, selbst in einer Einzelbenutzeranwendung mit einem Thread, ist das verwendete Identitätszuordnungsmuster. Dies bedeutet, dass jedes Mal, wenn Sie Daten mithilfe einer Abfrage oder einer ID abrufen, die abgerufenen Entitätsinstanzen im Cache bleiben. Wenn Sie das nächste Mal dieselbe Entität abrufen, erhalten Sie die zwischengespeicherte Instanz der Entität, sofern verfügbar, mit allen Änderungen, die Sie in derselben Sitzung vorgenommen haben. Dies ist erforderlich, damit die SaveChanges-Methode nicht zu mehreren verschiedenen Entitätsinstanzen desselben Datenbankdatensatzes führt. Andernfalls müsste der Kontext die Daten aller dieser Entitätsinstanzen irgendwie zusammenführen.

Der Grund für das Problem ist, dass ein Singleton-DbContext zu einer Zeitbombe werden kann, die möglicherweise die gesamte Datenbank + den Overhead von .NET-Objekten im Speicher zwischenspeichert.

Es gibt Möglichkeiten, dieses Verhalten zu umgehen, indem nur Linq-Abfragen mit der .NoTracking()Erweiterungsmethode verwendet werden. Auch heutzutage haben PCs viel RAM. Aber normalerweise ist das nicht das gewünschte Verhalten.

Dmitry S.
quelle
Dies ist korrekt, aber Sie müssen davon ausgehen, dass der Garbage Collector funktioniert, wodurch dieses Problem virtueller als tatsächlich ist.
Tocqueville
3
Der Garbage Collector sammelt keine Objektinstanzen, die von einem aktiven statischen / Singleton-Objekt gehalten werden. Sie werden in der zweiten Generation des Haufens landen.
Dmitry S.
1

Ein weiteres Problem, auf das Sie bei Entity Framework besonders achten sollten, ist die Verwendung einer Kombination aus dem Erstellen neuer Entitäten, dem verzögerten Laden und dem anschließenden Verwenden dieser neuen Entitäten (aus demselben Kontext). Wenn Sie IDbSet.Create nicht verwenden (im Gegensatz zu nur neu), funktioniert das verzögerte Laden dieser Entität nicht, wenn sie aus dem Kontext abgerufen wird, in dem sie erstellt wurde. Beispiel:

 public class Foo {
     public string Id {get; set; }
     public string BarId {get; set; }
     // lazy loaded relationship to bar
     public virtual Bar Bar { get; set;}
 }
 var foo = new Foo {
     Id = "foo id"
     BarId = "some existing bar id"
 };
 dbContext.Set<Foo>().Add(foo);
 dbContext.SaveChanges();

 // some other code, using the same context
 var foo = dbContext.Set<Foo>().Find("foo id");
 var barProp = foo.Bar.SomeBarProp; // fails with null reference even though we have BarId set.
Ted Elliott
quelle