Warum ist es möglich, eine DbLinq Abfrage nach dem Aufruf von Dispose () auf der Datacontext aufzuzählen?
Frage
Aktualisieren - Die Antwort ist offensichtlich, dass DbLinq nicht Dispose()
ordnungsgemäß nicht implementiert. D'oh!
Die unten ist alles irgendwie irreführend - Fazit: DbLinq ist (noch) nicht entspricht LinqToSql, wie ich annehmen, als ich ursprünglich diese Frage gestellt. Verwenden Sie es mit Vorsicht!
Ich verwende das Repository-Muster mit DbLinq. Meine Repositoryobjekte implementieren IDisposable
und die Dispose()
Methode funktioniert nur, was - Anrufe Dispose()
auf der DataContext
. Jedes Mal, wenn ich ein Repository verwenden, ich habe es in einem using
Block wickeln, wie folgt aus:
public IEnumerable<Person> SelectPersons()
{
using (var repository = _repositorySource.GetPersonRepository())
{
return repository.GetAll(); // returns DataContext.Person as an IQueryable<Person>
}
}
Diese Methode gibt eine IEnumerable<Person>
, also wenn mein Verständnis korrekt ist, keine Abfrage der Datenbank tatsächlich erfolgt bis Enumerable<Person>
durchlaufen wird (zB indem sie sie in einer Liste oder ein Array konvertieren oder indem sie in einer foreach
-Schleife), wie in diesem Beispiel:
var persons = gateway.SelectPersons();
// Dispose() is fired here
var personViewModels = (
from b in persons
select new PersonViewModel
{
Id = b.Id,
Name = b.Name,
Age = b.Age,
OrdersCount = b.Order.Count()
}).ToList(); // executes queries
In diesem Beispiel wird Dispose()
genannt unmittelbar nach persons
Einstellung, die ein IEnumerable<Person>
ist, und das ist das einzige Mal, es aufgerufen wird.
So, drei Fragen:
- Wie funktionierts? Wie kann ein angeordnete
DataContext
noch die Datenbank für die Ergebnisse abfragen nach demDataContext
angeordnet wurde? - Was bedeutet
Dispose()
eigentlich tun? - Ich habe gehört, dass es nicht notwendig ist (siehe zB diese Frage ) ein
DataContext
zu entsorgen, aber mein Eindruck war, dass es keine schlechte Idee. Gibt es einen Grund nicht verfügen über eine DbLinqDataContext
?
Lösung
1 Wie funktionierts? Wie kann ein angeordnete Datacontext noch die Datenbank für die Ergebnisse abfragen, nachdem die Datacontext angeordnet wurde?
Es nicht Arbeit. Es gibt etwas, das Sie zeigt uns nicht. Ich vermute, dass entweder Ihre Repository-Klasse nicht die DataContext
richtig / zur richtigen Zeit nicht verfügen, oder dass Sie perfunctorily ToList()
am Ende jeder Abfrage schreiben, die vollständig die Abfrage Transformation negiert und verzögerte Ausführung Sie in der Regel erhalten.
Versuchen Sie, den folgenden Code in einer Test-App, I Garantie Sie, dass es eine ObjectDisposedException
werfen:
// Bad code; do not use, will throw exception.
IEnumerable<Person> people;
using (var context = new TestDataContext())
{
people = context.Person;
}
foreach (Person p in people)
{
Console.WriteLine(p.ID);
}
Dies ist der einfachste mögliche reproduzierbare Fall und es wird immer werfen. Auf der anderen Seite, wenn Sie people = context.Person.ToList()
stattdessen dann die Ergebnisse der Abfrage schreiben bereits aufgezählt innen den using
Block, die ich wette, ist das, was in Ihrem Fall passiert.
2 Was bedeutet Dispose () eigentlich?
Unter anderem legt er einen Flag, das anzeigt, dass der DataContext
angeordnet ist, die auf jeder nachfolgenden Abfrage überprüft wird und bewirkt, dass der DataContext
eine ObjectDisposedException
mit der Botschaft werfen Object name: 'DataContext accessed after Dispose.'.
Es schließt auch die Verbindung, wenn die DataContext
öffnete sie und ließ sie offen.
3 Ich habe gehört, dass es nicht notwendig ist (siehe zum Beispiel dieser Frage) ein Datacontext zu entsorgen, aber mein Eindruck war, dass es keine schlechte Idee. Gibt es einen Grund, nicht zu verfügen über eine LinqToSql Datacontext?
Es ist erforderlich, die Dispose
DataContext
, da es notwendig ist, jede andere Dispose
IDisposable
. Sie könnten möglicherweise Verbindungen auslaufen, wenn Sie die DataContext
entsorgen scheitern. Sie könnten auch aus dem DataContext
abgerufen Speicher, wenn eine der Einheiten Leck am Leben gehalten werden, da der Kontext eine interne Identität Cache für das Mustereinheit-of-Arbeit hält es implementiert. Aber selbst wenn nichts davon der Fall, es ist nicht Ihre Sorge , was die Dispose
Methode intern tut. Nehmen wir an, es tut etwas wichtig.
IDisposable
ist ein Vertrag , die sagt: „Bereinigung nicht automatisch sein;. Sie brauchen mich zu entsorgen, wenn Sie fertig sind“ Sie haben keine Garantien, ob das Objekt eine eigene Finalizerthread hat, die nach der aufräumt, wenn Sie Dispose
vergessen. Implementationen sind Änderungen vorbehalten, weshalb es ist keine gute Idee, auf dem beobachteten Verhalten verlassen, wie auf explizite Spezifikationen gegenüber.
Das Schlimmste, was passieren kann, wenn man eine IDisposable
mit einem leeren Dispose
Verfahren entsorgen ist, dass Sie ein paar CPU-Zyklen verschwenden. Das Schlimmste, was passieren kann, wenn man nicht ein IDisposable
mit einer nicht-trivialen Implementierung entsorgen es ist, dass Sie Ressourcen auslaufen. Die Auswahl hier ist offensichtlich; wenn Sie einen IDisposable
sehen, vergessen Sie nicht, es zu entsorgen.
Andere Tipps
"Personen" ist eine IEnumerable Sammlung, die Datacontext (Repository) ist nur erforderlich, um den .GetNew Anruf.
die von / select / etc Schlüsselwörter sind syntaktischer Zucker für Methoden Erweiterung im Namensraum System.Linq hinzugefügt. Diese Erweiterungsmethoden fügen Sie die IEnumerable Funktionalität Sie in Ihrer Abfrage verwenden, nicht die Datacontext. In der Tat können Sie all dies zu tun, ohne LINQ2SQL überhaupt zu verwenden, um programmatisch ein IEnumerable zu schaffen zu demonstrieren.
Wenn Sie versuchen, eine weitere Repository zu machen (Datacontext) nennt diese Objekte verwenden, das ist, wenn Sie einen Fehler erhalten werden.
Die IEnumerable Sammlung werden alle Datensätze aus Ihrem Repository enthalten, das ist, warum Sie nicht die Datacontext benötigen die Abfrage zu machen.
Erweiterungsmethoden: http://msdn.microsoft.com/en- us / library / bb383977.aspx
LINQ-Erweiterungsmethoden: http://msdn.microsoft.com/en-us/ Bibliothek / system.linq.enumerable_members.aspx
Tief im Inneren des API, werden Sie wahrscheinlich ein Verfahren sehen eine api wie diese verwenden:
http://msdn.microsoft. com / en-us / library / y6wy5a0f (v = VS.100) aspx
Wenn der Befehl ausgeführt wird, wird das zugehörige Verbindungsobjekt geschlossen wird, wenn das zugehörige Datareader-Objekt geschlossen ist.