Warum brauche ich eine ToList (), um veraltete Kontextfehler zu vermeiden?

8

Ich schreibe Code, um mit EntityFrameWork auf eine Datenbank zuzugreifen. Der Code ist:

%Vor%

GetRowsFromDb () verwendet LINQ, um die Datenbank abzufragen und die Ergebnisse mit ID zu filtern.

Ich habe ursprünglich die obige Methode ohne den ToList () -Aufruf geschrieben, aber als ich versuchte, auf Objekte im IEnumerable zuzugreifen, die zurückgegeben wurden, würde ich eine Ausnahme bezüglich des dbcontext erhalten, der bereits entsorgt wird. Ich verstehe nicht, wie der obige Code Dinge repariert, obwohl es dann funktioniert. Ich nehme an, dass ToList () das Objekt tief kopiert und dass dies vielleicht die erforderliche Trennung vom Kontext / der Datenbank liefert, aber das Originalobjekt sollte sicher benutzbar sein?

    
CalumMcCall 16.12.2014, 17:27
quelle

4 Antworten

8

Der Grund, warum Sie ToList , ToArray oder eine andere Methode aufrufen müssen, die die von EF zurückgegebenen Daten auflistet, ist, dass die Abfrageausführung in LINQ zurückgestellt ist: Die Daten werden erst verarbeitet Du nimmst es explizit. Zu dem Zeitpunkt, zu dem Ihre Methode den Kontext zurückgibt, durch den die Abfragedaten erhalten wurden, wird geschlossen (Ihr using -Block sorgt dafür, dass dies schnell geschieht), was die angezeigte Ausnahme verursacht.

Dies geschieht, damit der Code keine Zeit für die Verarbeitung der Daten aufwendet, die Sie nicht benötigen. Sie könnten beispielsweise Code schreiben, der die Daten auf der Client-Seite liest und in der Mitte anhält. Wenn die Ausführung der Abfrage nicht aufgeschoben würde, hätten Sie Zeit und Speicher dafür aufgewendet, den "Schluss" der Abfrage zu erhalten, nur um sie wegzuwerfen. Die verzögerte Ausführung gibt Ihnen die Kontrolle: Sie entscheiden, welche Daten Sie behalten möchten, oder Sie bringen die gesamte Sammlung in den Speicher, je nachdem, was Sie mit den Daten machen möchten.

    
dasblinkenlight 16.12.2014, 17:30
quelle
7

Wenn Sie .ToList() nicht aufrufen, wird das Aufzählungszeichen ausgewertet, nachdem Ihre using -Klausel abgeschlossen hat. Daher wird der Datenkontext vor der Auswertung der Abfrage entfernt.

IMO, sollten Sie in Erwägung ziehen, Ihr Repository damit zu beauftragen (indem Sie .ToList() aufrufen), da dieses Problem sonst für ein ausfließendes Implementierungsdetail repräsentativ ist.

    
Kirk Woll 16.12.2014 17:29
quelle
1

Ohne ToList() geben Sie nur den Enumerator zurück, nicht die tatsächliche Sammlung von Objekten. Die tatsächlichen Objekte werden abgerufen, wenn Sie versuchen, auf die Sammlung zuzugreifen. In diesem Fall benötigen Sie jedoch einen Kontext und ein Repository, da Sie von der Datenbank aus auf sie zugreifen. Aber da es bereits außerhalb des Geltungsbereichs der using -Klausel liegt, sind beide daher die Ausnahme.

    
PiotrWolkowski 16.12.2014 17:30
quelle
1
  

Ich nehme an, dass ToList () das Objekt tief kopiert

Nicht genau - bevor Sie ToList aufrufen, haben Sie nur eine Abfrage . Sie erhalten die Ergebnisse erst, wenn Sie sie auflisten oder über ToList , ToArray , etc in eine konkrete Sammlung umwandeln.

  

sicher sollte das ursprüngliche Objekt verwendbar sein?

Nein - es wurde entsorgt, damit Sie dem System mitteilen können, dass das Objekt seine Arbeit getan hat und nicht mehr benötigt wird. Die Tatsache, dass Sie noch eine nicht ausgeführte Abfrage haben, hält den Kontext nicht in einem verwendbaren Zustand.

    
D Stanley 16.12.2014 17:30
quelle