2010-02-18 10 views
8

Verwenden von Entity Framework in .NET Ich möchte eine Liste der von der Datenbank zurückgegebenen Elemente durchlaufen und Aktualisierungen vornehmen..NET EntityFramework: "Beim Starten einer Transaktion auf der Provider-Verbindung ist ein Fehler aufgetreten. Details siehe die innere Ausnahme"

var qry = (from c in DBEntities.Customer select c); 
foreach (Object item in qry) 
{ 
    item.FirstName = .... 
    ... etc, other code here 
    DBEntities.SaveChanges(); 
} 

Nach: http://social.msdn.microsoft.com/Forums/en/adodotnetentityframework/thread/8a337036-d288-48d4-80d4-89e5a51eddd9?ppud=4 S Hargroves schlägt auf eine IList Umwandlung und das ist die Lösung.

Ich habe es nicht versucht, ich bin mir sicher, dass es funktioniert, aber selbst es funktioniert, ich möchte wissen, warum ich das Element während der Schleife nicht aktualisieren kann? Dies geschieht in meiner lokalen Entwicklungsumgebung, ohne dass andere Benutzer auf die Datenbank treffen.

Dank ...

+0

Was hat die innere Ausnahme sagen? Im Allgemeinen sollten Sie Ausnahmen abfangen und dann das Ergebnis von 'ex.ToString()' posten. Du solltest dann "werfen"; da "ex.ToString()" die Ausnahme nicht behandelt. –

Antwort

3

ich mit der Herstellung der var eine Liste zustimmen würde. Dann in Ihrem foreach, anstatt Objekt Objekt in Qry zu verwenden, verwenden Sie Kunde Kunde in Qry. In diesem Szenario arbeiten Sie wirklich mit Kundenobjekten, nicht nur mit Objekten. In den meisten Fällen möchten Sie SaveChanges() nicht in einem Foreach aufrufen, da bei jeder Ausführung ein Update-Befehl auf dem Server ausgeführt wird. Wenn du es nach der foreach machst, wird es einen Batch von Aufrufen an die Datenbank machen und viel schöner durchführen.

Mein vorgeschlagenen Pseudo-Code sieht so etwas wie

var customers = (from c in DBEntities.Customer select c).ToList<Customer>(); 
foreach (Customer customer item in customers) 
{ 
    customer.FirstName = .... 
    ... etc, other code here 

} 
DBEntities.SaveChanges(); 
0

Vielen Dank für die Empfehlung an Saving nach Schleife, hatte ich nicht gedacht. Allerdings muss ich mehr als 1 Million Datensätze verarbeiten, das ist nicht so viel, aber es gibt etwas Verarbeitung, die während jeder Schleife durchgeführt wird. Ich bin ein wenig besorgt, dass es sehr viel Zeit kosten wird, die 1 Million Datensätze, die die Informationen aktualisieren, zu durchlaufen und dann eine Weile zu brauchen, um die Änderungen zu veröffentlichen.

Ich weiß auch, dass das EntityFramework wahrscheinlich nicht der beste Ansatz ist, aber ich bin daran interessiert, Funktionen und Einschränkungen von Entity Framework zu lernen.

Auch nur zu beachten, die Var-Liste gibt tatsächlich eine ObjectQuery des Customer-Typs zurück. Daher kann die foreach-Schleife tatsächlich wie oben beschrieben geschrieben werden, indem der Datentyp "Kunde" verwendet wird, ohne dass eine Konvertierung in eine Liste erfolgt.

Wieder ist meine Frage, die ich gerne wissen würde, warum kann ich eine Änderung im gleichen Kontextobjekt (DBEntities) während der Schleife nicht veröffentlichen?

+2

Sie posten keine weiteren Informationen als Antwort auf Ihre Frage, sondern bearbeiten Ihre ursprüngliche Frage. – StarCub

11

Wenn Sie die Datenbank mit SaveChanges für eine Abfrage aktualisieren, wird die Abfrage ungültig gemacht. Die Ergebnismenge wurde möglicherweise durch das von Ihnen durchgeführte Update geändert.

Mit ToList lösen Sie die Ausführung der Abfrage aus und bringen alle Ergebnisse aus der Datenbank in den Speicher. Ihre In-Memory-Liste ist jetzt konkreter und nicht mehr daran interessiert, eine Abfrage zu sein.

Da Objektabfragen IEnumerable verwenden, ist es nicht in Ordnung, etwas zu tun, das die Liste in einer foreach ändert.

Ich glaube auch dieser Code für die gleichen grundlegenden Gründen scheitern würde:

List<int> numbers = new List<int>() { 1,2,3,4,5,6}; 
foreach(var num in numbers) 
    numbers.Remove(num); //Invalidates the Enumerator being used in the foreach 
+0

Der Aufruf von 'ToList' kann eine Lösung sein, aber was ist, wenn Ihre Anfrage 50.000 Datensätze oder mehr enthält? Es kann sein und kann möglicherweise zu viele Daten sein, um sofort in den Speicher zu ziehen. –

+0

Der ursprüngliche Code hätte das gleiche Problem. Soweit ich weiß, führt EF keine "Paging" von Ergebnissen beim Aufzählen einer ObjectQuery durch. Sie können eine Möglichkeit finden, die ursprüngliche Abfrage in Batches zu unterteilen oder die beiden Kontextoptionen zu verwenden, wie @Ron – Tilendor

3

Ok Ich habe in der gleichen Ausgabe lief. Momentan habe ich keine Million Datensätze, sondern nur etwa 20K, aber die Tabelle, die ich verarbeiten möchte, speichert Bilder, so dass die Verarbeitung der Tabelle zu einer Liste viel zu lange dauert, sogar auf einer Desktop-App.

Ich benutze LinqToSql seit es herauskam und es funktioniert gut in LinqToSql, also war ich etwas sauer, als ich sah, dass es in Entity nicht funktioniert. Und es ist dumm, dass Microsoft es in Entity nicht geschafft hat, aber hier ist die Arbeit herum. Stellen Sie 2 Context-Objekte her. Eine für die Liste und eine für die Updates wie folgt.

entityList _imgList = new entityList(); 
entityList _imgSave = new entityList(); 

// Now the 1st time I did this I got the whole record like follows. 

    var _imgList = _imgList.Images.where(i=> i.NotProcessed == false); 
    foreach(Images _img_p in imgList) 
    { 
     if(something) 
     { 
      Images _img = _imgSave.Single(i=> i.ID == _img_p.ID); 
      _img.NotProcessed == true; 
      imgSave.SaveChanges(); 
     } 
    } 
imgList.dispose(); 
imgSave.dispose(); 


// After i verified this worked I figured why do I need to whole record to loop though so I changed it to just get the ID then process my loop as follows, and it works great. 

    var _imgIds = _imgList.Images.where(i=> i.NotProcessed == false).select(i=>i.ID); 
    foreach(long _imgID in imgList) 
    { 
     Images _img = _imgSave.Single(i=> i.ID == _imgID); 
     if(something) 
     { 
      _img.NotProcessed == true; 
      imgSave.SaveChanges(); 
     } 
    } 

imgList.dispose(); 
imgSave.dispose(); 

Sie können mehr an meinem Blog sehen Post (ASP.Net Help Blog)

+0

P.S. Speichern von Änderungen After-Loop funktioniert, aber wenn Sie die Änderungen live zum Zeitpunkt des Looks passieren müssen, tut es nicht – Ron

Verwandte Themen