Seit Einiger Zeit haben wir diesen Fehler in unserem Hauseigenem Support-Ticket System.
Heute konnte ich diesen Fehler nachstellen und möchte ihn hier erklären.
Es geht um folgenden Code, in dem ein Datensatz in einer schleife geprüft wird, welche durch eine LINQ Abfrage erstellt wurde:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var alleSupportfaelle = from tSupportfaelle in _DB.supportfaelle select tSupportfaelle; foreach (var Suportfall in alleSupportfaelle) { // !!! In der folgenden Abfrage passiert der Fehler !!! int CountAnsprechpartner = ( from tAnsprechpartner in _DB.ansprechpartner where tAnsprechpartner.kunden_id == Suportfall.kunden_id && tAnsprechpartner.nachname == Suportfall.ansprechpartner select tAnsprechpartner).Count(); if (CountAnsprechpartner == 0) { // Mache irgendwas mit dem Ansprechpartner } } |
Was jetzt passiert, denn man den Code ausführt, ist dieser Fehler:
There is already an open datareader assiciated with this connection, which must be closed first.
Jetzt die Phänomenal logische Begründung:
Mit der ersten LINQ-Abfrage oben, in der wir die Support-Tickets aus der Datenbank holen, erstellen wir einen DataReader.
Dieser wird danach von der Vorschleife benutzt um durch die Elemente aus dem DataReader zu Iterieren.
Damit ist der DataReader der LINQ Abfrage innerhalb der foreach-Schleife immer noch geöffnet.
Möchte man nun innerhalb der foreach schleife eine weitere LINQ-Abfrage machen, muss man zuerst sicher stellen, dass der DataReader geschlossen ist.
Wie soll man dies aber tun?
Ist eigentlich sehr einfach:
Nicht direkt mit dem Result der Abfrage arbeiten, sondern das Result zuerst z.b. in eine Liste schreiben.
Damit liegt das Result der Abfrage lokal im RAM und wird von dort aus auch benutzt.
Der DataReader ist somit in der Schleife geschlossen und kann erneut durch eine andere Abfrage geöffnet werden.
Am ende Muss der Code dann wie folgt aussehen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | var alleSupportfaelle = (from tSupportfaelle in _DB.supportfaelle select tSupportfaelle).ToList(); // !!!Geändert: ToList() um das Result in eine Liste zu schreiben !!! foreach (var Suportfall in alleSupportfaelle) { // !!! In der folgenden Abfrage passiert der Fehler jetzt nicht mehr !!! int CountAnsprechpartner = ( from tAnsprechpartner in _DB.ansprechpartner where tAnsprechpartner.kunden_id == Suportfall.kunden_id && tAnsprechpartner.nachname == Suportfall.ansprechpartner select tAnsprechpartner).Count(); if (CountAnsprechpartner == 0) { // Mache irgendwas mit dem Ansprechpartner } } |
Hey Sven,
wenn Du die Connection von Linq einfach offenhälst, also zu Beginn mit .Open() öffnest,
kannst Du im Connectionstring auch den Parameter „MultipleActiveResultSets=true;“ mitgeben, das macht das dann alles etwas einfacher 😉
Sollte aber auch bei nicht direktem oder persistentem Öffnen funktionieren…
Ich habs dem Lucas schon als Mail geschrieben, aber hier noch mal für alle anderen:
Es hadelt sich bei diesem Problem um eine MySQL Datenbank.
MySQL hat leider bislang noch kein MARS eingebaut, weshalb ich den Tip vom Lucas leider nicht nachkommen kann. 🙂
Trotzdem Danke für den Kommentar!