Dieser Artikel wurde maschinell übersetzt.

Datenpunkte

Ein paar meiner Lieblings-Dinge... in der Entity Framework 4.2 DbContext

Julie Lerman

Julie LermanNoch bevor Anfang 2011 Entity Framework 4.1 veröffentlicht wurde, konzentrierten Entwickler nur die Hälfte was uns, in diesem Paket gegeben wurde: Landesvorwahl zuerst. Code zunächst können Sie Ihre Entitätsdatenmodell mit Ihrer Domäne Klassen und Code erste Konfigurationen, eine großartige Alternative zu Entwickler aussprechen, die nicht, dass den visuellen Designer verwenden, um das Modell zu definieren möchten. Aber jedes Bit des Beispielcodes, die Sie für die Verwendung von Entity Framework (EF) mit diesen Klassen und Code erste definierte Modelle sehen ist ein weiteres sehr wichtiges Merkmal, das in EF 4.1 kam getrieben: die DbContext-Klasse.

Die ObjectContext-Klasse ist Teil der Kern-EF-API in Microsoft.NET Framework 4 und ist Klasse, mit dem Sie Abfragen durchführen, Nachverfolgung von Änderungen und Aktualisieren der Datenbank mit die stark typisierten Klassen, die Ihr Modell darstellen. Klasse DbContext ist am besten beschreiben, wie ein Wrapper um ObjectContext, der am meisten allgemein verfügbar macht Features von ObjectContext verwendet sowie einige einfacheren "Abkürzungen" um Aufgaben, die häufig verwendet, sind aber kompliziert zu Code direkt mit ObjectContext.

Es ist meine Lenkung und Microsoft, dass Sie DbContext zuerst beim Beginn neuer Projekte mit EF berücksichtigen sollten. Wenn Sie feststellen, dass Sie gelegentlich müssen einige detailliertere Logik zuzugreifen, die ObjectContext-Klasse bereitgestellt, wird, gibt es ein Haken seine zugrunde liegenden ObjectContext eine Instanz DbContext einholen:

var objectContext = (myDbContextInstance as IObjectContextAdapter).ObjectContext

Wenn Sie wissen, dass Sie Arbeit durchführen müssen, die häufige Verwendung von ObjectContext Funktionen direkt erfordert, können Sie es vorziehen, verwenden anstatt DbContext. Aber im Allgemeinen das EF-Team empfiehlt, dass Sie ObjectContext direkt verwenden vermeiden, es sei denn, Sie sind mit DbContext aus irgendeinem Grund verhindert.

Ich werde die Einschränkung hinzufügen, die diese Anleitung für neue Projekte gemeint ist. Beim Arbeiten mit dem DbContext-API erhalten Sie nicht nur neue schlanker und intelligenter DbContext Klasse, aber auch ebenso verbesserte DbSet und DbQuery-Klassen (Gegenstücke zu ObjectSet und ObjectQuery).

Obwohl ich ein großer Fan von den DbContext bin, sind ein paar von seinen Funktionen mein favorite kleine Haustiere geworden.

DbSet.Find

Eine der neuen Methoden in der API ist DbSet.Find. Dies hilft mit einem gemeinsamen Muster Entwickler für den Datenzugriff: ein einzelnes Objekt basierend auf ihren Primärschlüssel abrufen.

Mit ObjectContext müssten Sie eine vollständige Abfrage erstellen und führen Sie dann die Abfrage mithilfe einer LINQ-Methode z. B. SingleOrDefault.

Das würde so aussehen:

var partyHatQuery = from p in context.PartyHats where p.Id == 3 select p;
var partyHatInstance = partyHatQuery.SingleOrDefault();

Sie könnten, die effizienter mit LINQ-Methoden und einen Lambda-Ausdruck schreiben:

var partyHatInstance = context.PartyHats.SingleOrDefault(p => p.Id == 3);

Wie oft haben Sie Abfragen ausgeführt, die diese einfache Aufgabe durchführen? Sie können diesen Code sogar in eigene einfachere Methode abstrahiert, haben.

Dies ist, was das EF-Team für Sie in der API DbContext habe. Beim Arbeiten mit DbContext wäre PartyHats ein DbSet <PartyHat>, und die DbSet.Find-Methode können Sie um die Ausführung die gleichen Abfrage mit schnell zu erreichen:

context.PartyHats.Find(3)

Diese Methode setzt der Wert Sie angeben ist der Schlüsselwert für die Klasse, die Sie suchen – in diesem Fall PartyHat. EF führt dann eine Abfrage SingleOrDefault in Ihrem Namen, wo Id gleich dem Wert übergebenen ist, Daten suchen – in diesem Fall 3. Sie werden wahrscheinlich in einer Variable, nicht auf einen tatsächlichen Wert übergeben.

Es ist ein weiterer Vorteil für die DbSet.Find-Methode, die Sie mit einer Abfrage nicht erreichen können. Die Find-Methode sucht zunächst für ein übereinstimmendes Objekt im Speicher, die durch den Kontext nachverfolgt wird. Wenn diese gefunden ist, stören nicht EF die Datenbank abfragt. Dies ist wesentlich effizienter als das Ausführen einer Abfrage in der Datenbank nur auf die Ergebnisse der Abfrage wegwerfen, wenn die Objektinstanz bereits im Speicher ist — eine vergeudete Reise mit der Datenbank, die viele Entwickler auslösen, ohne es zu merken.

Sie können auch DbSet.Find mit zusammengesetzte Schlüssel verwenden. Die Signatur von Find ist kein einzelnes Objekt nehmen sondern ein Parameterarray. Daher können Sie in einer Liste von Werten, die die Werte darstellen, aus denen sich der Schlüssel übergeben.

DbSet.Local

Beim Arbeiten mit EF fand ich häufig mich wollend zu ausführen etwas mit Objekten, die bereits im Speicher und wird durch einen Kontext verfolgt wurden. Typische Orte für diese Logik sind in der SaveChanges Überschreibung oder SavingChanges-Methode, wo ich eine Validierung durchführen werde. (Dank der neuen Validierung-API, die zusammen mit DbContext verfügbar ist, habe ich viel von dieser Logik zu reduzieren konnte. Aber wird nicht besprochen Validierung in dieser Spalte.)

ObjectContext bietet eine Möglichkeit, Objekte zu entdecken, die sie verfolgt, aber die API-Logik dazu ist weder leicht zu finden noch leicht zu Code. In der Tat, in meinem Buch "Programming Entity Framework" (O' Reilly Media, 2010), schrieb ich eine Reihe von vier Erweiterungen der Methode zu helfen, diese Aufgabe einfacher und flexibler gestalten.

Häufiger, aber wissen Entwickler nicht den Unterschied zwischen Ausführen einer LINQ to Entities-Abfrage auf den Kontext und die Interaktion mit dieser Objekte, die bereits der Kontext nachverfolgt. Zum Beispiel, habe ich viel Code, wo ein Entwickler mithilfe einer Abfrage Daten abruft und dann versucht, führen Sie Logik auf was jetzt von der Abfrage verwaltet wird:

var balloons = context.Balloons.Where(b => b.Size == "L").ToList();
 var balloonCount = context.Balloons.Count();

In der Tat sind zwei separate Abfragen. Die zweite Zeile des Codes führt eine andere Abfrage in der Datenbank und gibt die Anzahl der alle Ballons zurück. In der Regel, was der Entwickler beabsichtigt hatte war eine Zählung der Ergebnisse erhalten — d. h. Ballons.Zählen.

Wenn Sie keinen Zugriff auf eine Variable, aber immer noch herauszufinden, wie viele Ballon-Objekte ein ObjectContext verfolgt möchten, gibt es eine Möglichkeit herauszufinden, aber es ist nicht einfach: ObjectContext verfügbar macht eine ObjectState­Manager, die eine Methode namens GetObjectStateEntries hat. Diese Methode erfordert, dass Sie in einem oder mehreren EntityState-Enumerationen (z. B. hinzugefügt, geändert und so weiter) übergeben, so dass es, welche Einträge weiß zurückgegeben. Obwohl die Ergebnisse abgefragt werden, Filtern ist unhandlich und sogar dann was es gibt ist nicht Ihre Entitäten, sondern die ObjectStateEntry-Instanzen, die Statusinformationen über Ihre Objekte darstellen.

Dies bedeutet, dass ohne den Einsatz von meinem Erweiterungsmethoden, Code, um die Anzahl der Ballone im Speicher abzurufen wie folgt aussieht:

objectContext.ObjectStateManager
 .GetObjectStateEntries(EntityState.Added |
                        EntityState.Modified | EntityState.Unchanged)
 .Where(e => e.Entity is Balloon).Count();

Wenn Sie die Ballon-Objekte, nicht nur die Instanzen den ObjectStateEntry, erfassen möchten, dann müssen Sie einige benötigte die ObjectStateEntry.Entity Rückgabetypen als Sprechblasen hinzufügen:

objectContext.ObjectStateManager
 .GetObjectStateEntries(EntityState.Added |
                        EntityState.Modified | EntityState.Unchanged)
 .Where(e => e.Entity is Balloon)
 .Select(e => e.Entity as Balloon);

Dieser Code sehen, vielleicht machen Sie die neue Eigenschaft DbSet.Local schätzen, fast so viel wie ich tun.

Verwenden DbSet.Local um alle nachverfolgten Ballon-Instanzen aus dem Kontext zu erhalten, rufen Sie einfach:

context.Balloons.Local;

"Local" gibt ein ObservableCollection-Objekt, das zwei Vorteile bietet. Die erste ist, dass es kann abgefragt werden, damit Sie zurückkehren können, welche Teilmenge der lokal zwischengespeicherten Ballone werden soll. Das zweite ist, dass Ihr Code (oder Komponenten z. B. Datenbindungs-Steuerelemente) können überwachen und reagieren auf Objekte hinzugefügt oder aus dem Cache entfernt wird.

Neben der sichtbar-Eigenschaft und der reduzierte Code gibt es zwei weitere bemerkenswerte Unterschiede zwischen der Verwendung von DbSet.Local und GetObjectStateEntries. Eine ist, dass lokale Objekte, von der bestimmten DbSet nur zurückgibt, während GetObjectStateEntries Einträge unabhängig von der Art der Objekte zurückgibt, die sie darstellen. Der andere Unterschied ist, dass lokal wird nicht zurückkehren, dass Objekte, die der Kontext kennt als Deleted gekennzeichnet sind. Mit GetObjectStateEntries haben Sie Zugriff auf Added, Modified, Unchanged und gelöschte Objekte gemäß der Liste der Parameter, die Sie für die Methode bereitstellen.

NoTracking LINQ-Abfragen

Wenn Leistung mit Kunden sprechen, empfehle ich oft, dass sie nutzen die EF-Fähigkeit, die Daten zurückgeben, die nicht durch den Kontext nachverfolgt werden muss. Beispielsweise Sie möglicherweise Daten, die Sie für eine Dropdown-Auswahlliste angeben müssen. Sie müssen nie Änderungen an diesen Daten, viel weniger die Datenbank beizubehalten. Daher ist es klug, um die Leistungsbeeinträchtigung Treffer bei EF ObjectStateEntry Instanzen für jedes Objekt es erstellt, Tracking ist, als auch zwingen, den Kontext zu kennen an diesen Objekten vorgenommenen Änderungen berücksichtigt.

Aber mit ObjectContext, die NoTracking-Unterstützung ist nur über die ObjectQuery-Klasse, nicht von LINQ to Entities-Abfragen verfügbar.

Hier ist ein typisches Beispiel des Erhaltens einer NoTracking-Abfrage mithilfe ein ObjectContext (Kontext genannt):

string entitySQL = " SELECT p, p.Filling " +
                           "FROM PartyContext.Pinatas AS p " +
                           "WHERE p.Filling.Description='Candy'";
var query=context.CreateQuery<DbDataRecord>(entitySQL);
query.MergeOption = System.Data.Objects.MergeOption.NoTracking;
var pinatasWithFilling=query.ToList();

Die abgerufenen Piñatas und Füllungen wäre Objekte im Arbeitsspeicher, aber im Kontext würde keine Kenntnis davon haben.

Allerdings würden Sie die folgende LINQ to Entities-Abfrage, verwenden, die eine IQueryable, keine ObjectQuery gibt wäre es keine MergeOption-Eigenschaft:

context.Pinatas.Include("Filling")
  .Where(p=>p.Filling.Description=="Candy")

Eine Lösung ist, die LINQ-Abfrage an eine ObjectQuery gegossen und legen Sie dann die MergeOption. Dies ist nicht nur nicht offensichtlich, aber auch klobig.

Dies zu erkennen, das EF-Team fand einen Weg, damit Sie Ihre Partei Kuchen und Essen sie, auch mit der neuen AsNoTracking-Erweiterungsmethode für IQueryables, die Teil der DbContext-API ist. Jetzt kann ich es auf meine LINQ-Abfrage auf tack:

context.Pinatas.Include("Filling")
  .Where(p=>p.Filling.Description=="Candy")
  .AsNoTracking();

Eine Reihe von Pinatas und Füllungen, die durch den Kontext werden ignoriert, wird zurückgegeben. EF nicht Wastethe aufs DbEntityEntry Objekte (die DbContext API Version von ObjectStateEntry) für jedes Objekt zu instanziieren. Noch wird es verschwenden die Mühe Rahmen zu zwingen, diese Objekte zu überprüfen, wenn DetectChanges aufgerufen wird.

Es ist einfach zu Code und sehr über IntelliSense erkennbar.

Tüpfelchen auf dem i

Diese drei Funktionen — finden, lokalen und AsNoTracking — nicht ermöglichen es mir, die Aufgaben, die nicht mit dem ObjectContext erreichbar waren. Aber sie mich glücklich machen, jedes Mal, wenn ich sie benutzen. Es gibt so viele Programmieraufgaben, die den DbContext-API vereinfacht (im Vergleich zur Verwendung von ObjectContext), daß es wurde gestrafft meine Anwendungsentwicklung ganz ein wenig. Ich habe auch an alten ObjectContext-Code zurückgegeben und DbContext zusammen mit ersten Code verwenden und konnten deutlich zu reduzieren die Menge an Code in jene apps umgestaltet. Aber für Entwickler, die nicht so vertraut mit der EF, wie ich bin, die Auffindbarkeit von so vielen seiner Fähigkeiten machen einen großen Unterschied für aufstehen und laufen mit ihm.

Julie Lerman ist ein Microsoft MVP.NET Mentor und Berater, der lebt in den Bergen von Vermont. Finden Sie ihre Präsentation auf Daten zugreifen und andere Microsoft.NET-Themen-Benutzergruppen und Konferenzen auf der ganzen Welt. She Blogs auf thedatafarm.com/blog und ist der Autor von "Programming Entity Framework" (2010) und "Programming Entity Framework: Code-First"(2011), beide von O' Reilly Media. Folgen sie auf Twitter bei twitter.com/julielerman.

Dank der folgenden technischen Experten für die Überprüfung dieses Artikels: Arthur Vickers