Freigeben über



Januar 2017

Band 32, Nummer 1

Data Points – EF Core 1.1: Besonders wichtige Merkmale

Von Julie Lerman

Julie LermanEntity Framework (EF) Core 1.1 wurde gerade veröffentlicht, als ich mit dem Schreiben dieser Kolumne begonnen habe (November 2016). Zwischen Release 1.0 und 1.1 sind einige signifikante Dinge geschehen. Insbesondere hat der Patch 1.0.1 einige wichtige Programmfehler behoben, die bei der Veröffentlichung von Version 1.0 erkannt wurden. Eine ausführliche Liste dieser Fixes finden Sie in den Anmerkungen zur Version unter bit.ly/2fl5xNE. Die meisten dieser Fixes beziehen sich darauf, wie LINQ-Abfragen in SQL transformiert werden. Es sind jedoch auch Fixes am Modell-Generator, zur Persistenz über SaveChanges und zu Migrationen verfügbar.

EF Core 1.1 enthält weitere Programmfehlerbehebungen, zahlreiche Optimierungen für die Interpretation von LINQ-Abfragen sowie erhebliche Leistungssteigerungen. Außerdem werden neue Features eingeführt. Einige davon waren bereits in EF6 vorhanden, wurden aber nicht in EF Core 1.0 übernommen, was dazu führte, dass sich viele Entwickler EF Core nicht einmal angesehen haben. Andere Features sind komplett neu. Ich möchte Ihnen in diesem Artikel eine Zusammenfassung dieser Änderungen vorstellen und dann einige Aspekte hervorheben, die für mich äußerst interessant sind. Außerdem stelle ich Links zu den zahlreichen wertvollen Ressourcen bereit, die ich selbst dafür nutze, die Entwicklung von EF Core zu verfolgen. Viele dieser Informationen werden in den Doks (docs.microsoft.com/ef) und in den Beiträgen des Teamblogs (bit.ly/2ehZBUB) behandelt.

Insbesondere sollten Sie Arthur Vickers Blog im Auge behalten. Arthur ist ein erfahrener Entwickler, der seit der Einführung von POCO-Unterstützung in EF Mitglied des Teams ist. Er ist wesentlich an der Modernisierung von EF beteiligt. Sie finden eine sehr lesenswerte Serie seiner Beiträge zu EF Core 1.1 unter blog.oneunicorn.com.

Microsoft plant, zahlreiche EF6-Features in EF Core zu übernehmen. Dies gilt jedoch nicht für alle Features. Außerdem sind einige neue Features für zukünftige Versionen geplant. Zurzeit konzentriert sich EF Core 1.1 auf Upgrades, durch die EF Core für eine größere Anzahl von Entwicklern interessant sein könnte. Im Folgenden finden Sie die wichtigsten dieser Features.

Jetzt in EF 1.1 enthaltene EF6-Features

Die DbSet.Find-Methode, die mit der Einführung der DbContext-API in EF 4.1 verfügbar wurde, fand nicht ihren Weg auf die Hitliste für die erste Iteration von EF Core. Viele Entwickler waren darüber verärgert. Diese Methode ist weit mehr als eine bequeme Möglichkeit, eine Entität effizient basierend auf ihrem Schlüsselwert abzufragen. Sie überprüft zuerst, ob die betreffende Entität bereits im Arbeitsspeicher vorhanden ist und von EF nachverfolgt wird. Wenn die Entität nicht im DbContext-Cache gefunden wird, führt EF eine FirstOrDefault-Abfrage für die Datenbank aus, um die Entität abzurufen. Dabei handelte es sich in EF6 und früheren Versionen um eine SingleOrDefault-Abfrage. Die Find-Methode ist dafür konzipiert, eine nicht erforderliche Verwendung der Datenbank zu vermeiden. Dies führt zu einem Leistungsvorteil. Wenn Sie wie ich an den Details interessiert sind, finden Sie den Code in der EntityFinder-Klasse auf GitHub  (bit.ly/2e9V0Uu).

Ein weiterer großer Unterschied besteht darin, dass sich die Find-Methode jetzt in einem EntityFinder-Dienst befindet. Es handelt sich nicht mehr nur eine Methode, die direkt in einer internen DbSet-Klasse wie in EF6 implementiert ist. EF Core besteht aus Hunderten von Diensten zum Kapseln bestimmter Tasks. In seinen Demos im Channel 9-Video zu EF Core 1.1 (bit.ly/2fHOCsN) zeigt Rowan Miller das direkte Verwenden von Diensten sowie deren Ersetzung.

Bestandteil von EF Core wird mit Update 1.1 nun auch das EF6-Feature, das als Verbindungsresilienz bezeichnet wird. Es bietet Unterstützung für die einfache Behandlung vorübergehender Verbindungsprobleme, die auftreten können, wenn eine Remotedatenbank wie die Azure SQL-Datenbank verwendet wird. Die EnableRetryOnFailure-Erweiterungsmethode des SQL-Datenbankanbieters kann in DbContext.OnConfiguring oder im AddDbcontext-Aufruf in „Startup.cs“ festgelegt werden, wenn Sie ASP.NET Core-Abhängigkeitsinjektion verwenden. EnableRetryOnFailure ruft SqlServer­RetryingExecutionStrategy auf. Dieses Objekt erbt vom ExecutionStrategy-Typ. Sie können Ihre eigene ExcecutionStrategy erstellen und festlegen, und andere Anbieter können ebenfalls ihre eigenen ExecutionStrategy-Konfigurationen vordefinieren. Falls Sie mit diesem Feature nicht vertraut sind: Es ähnelt DbExecutionStrategy von EF6. Dieses Objekt habe ich ausführlich in meinem Pluralsight-Kurs „EF6 Ninja Edition“ (bit.ly/PS_EF6) behandelt.

EF hat schon immer drei Möglichkeiten zum Laden in Beziehung stehender Daten bereitgestellt. Die erste (Eager Loading) wird durch die DbSet.Include-Methode zum Abrufen von Datendiagrammen in einer einzigen Abfrage aktiviert. Zwei weitere Möglichkeiten laden im Gegensatz dazu in Beziehung stehende Daten, nachdem sich die Hauptobjekte bereits im Arbeitsspeicher befinden und sich der DbContext, der diese nachverfolgt, noch im Bereich befindet. Bei Lazy Loading (träges Laden) werden in Beziehung stehende Daten automatisch bei Bedarf abgerufen, während beim expliziten Laden EF explizit angewiesen wird, die in Beziehung stehenden Daten zu laden. „Include“ wurde zuerst in EF Core implementiert und mit EF Core 1.0 zur Verfügung gestellt. Es wurden sogar einige nette Optimierungen im Vergleich zu den Versionen EF6 oder früher angebracht. Das explizite Laden mit der Load-Methode wurde nun in EF Core 1.1 hinzugefügt. Lazy Loading wird noch nicht unterstützt, wurde aber in Aussicht gestellt.

Mit den Änderungsprotokollierungs-APIs von DbContext können Sie direkt auf Änderungsprotokollierungsinformationen zugreifen und z. B. den Zustand einer Entität mit der DbContext.Entry(einObjekt).State-Methode abrufen oder festlegen. Mit EF6 ist eine umfassendere Kontrolle mithilfe neuer Methoden wie GetDatabase­Values, CurrentValues und OriginalValues möglich. Diese Methoden sind nun in EF Core 1.1 verfügbar.

Neue Funktionen in EF 1.1

EF Core enthält zahlreiche Features, die in früheren Versionen noch nicht vorhanden waren. Die folgende kurze Liste nennt einige Beispiele: Batchverarbeitung während SaveChanges, eindeutige Fremdschlüssel, der wunderbare InMemory-Anbieter zum Testen, intelligentere LINQ-Abfrageverarbeitung und intelligentere und einfachere Fluent-Zuordnungen.

EF 1.1 verfügt über zusätzliche neue Features, von denen ich eines als großer Fan von DDD (Domain-Driven Design) besonders schätze: Unterstützung für gekapselte Sammlungen.

Zugeordnete Felder und gekapselte Sammlungen. EF Code First hat immer nur die Zuordnung zu Eigenschaften unterstützt, die einen Getter und einen Setter besitzen (selbst wenn der Setter privat ist). Außerdem musste die Eigenschaft für Sammlungsnavigationen eine ICollection sein. Wenn Sie einschränken möchten, wie die Werte von Eigenschaften mit Daten aufgefüllt werden, ist eine Möglichkeit zum Kapseln der Eigenschaft unabdingbar: Auf diese Weise können Sie bei jeder Verwendung Ihrer Klasse erzwingen, dass eine öffentliche Methode eingesetzt wird, damit sichergestellt ist, dass die Geschäftsregeln um diese Eigenschaft eingehalten werden. EF6 und frühere Versionen ermöglichen das Kapseln skalarer Eigenschaften, indem der Setter als privat markiert wird. Es besteht jedoch keine Möglichkeit, Sammlungen wirklich zu kapseln und zu verhindern, dass die Sammlung direkt geändert wird.

Mit EF 1.1 können nun direkte Zuordnungen zu Feldern sowie zu IEnumerable-Eigenschaften erfolgen. Die neue Möglichkeit von Zuordnungen zu Feldern und nicht nur Eigenschaften erlaubt die Verwendung einer direkteren Vorgehensweise als das Verbergen des Setters. Außerdem werden einige zusätzliche Methoden zum Kapseln skalarer Werte unterstützt. Die folgende Eigenschaft DueDate verfügt über einen Getter, nicht jedoch über einen Setter. Außerdem weist sie das Feld _dueDate auf, das an die Eigenschaft gebunden ist:

private DateTime _dueDate;
public DateTime DueDate {
  get { return _dueDate;
  }
}

Die einzige Möglichkeit, DueDate festzulegen, besteht im Aufrufen der CalculateDueDate-Methode, die das Feld ändert:

private void CalculateDueDate() {
  _dueDate=Start.AddDays(DaysLoaned);
}

EF Core 1.1 erfordert z. B. beim Zurückgeben der Ergebnisse einer Abfrage eine explizite Zuordnung im DbContext, um EF zu informieren, dass das Feld _dueDate für die Zuordnung zur Datenbank verwendet werden kann. Sie müssen die API-Methoden „Property“ (und optional HasField) zum Angeben verwenden, dass das Feld _dueDate ein Platzhalter für die Eigenschaft DueDate ist. Da der Feldname _dueDate einer EF-Konvention genügt, muss ich in diesem Fall nicht die HasField-Methode verwenden. Ich habe sie jedoch hinzugefügt, damit Sie sich die Methode ansehen können:

protected override void OnModelCreating(ModelBuilder modelBuilder) {
  modelBuilder.Entity<BookLoan>().Property(bl => bl.DueDate)
  .HasField(“_dueDate”);
}

Es konnten schon private Setter verwendet werden, bevor die Feldzuordnung verfügbar war. Es gab jedoch keine Möglichkeit, Sammlungen zu kapseln, um zu verhindern, dass niemand eine Sammlung direkt über ihre Add- oder Remove-Methoden bearbeiten konnte. Zu diesem Zweck muss nicht der Setter verborgen werden, sondern die Sammlungsmethoden. Ein gängiger Ansatz in DDD besteht darin, die Eigenschaft in ein IEnumerable umzuwandeln. In EF6 und früheren Versionen kann die Zuordnung jedoch nur zu einem Typ einer ICollection erfolgen, IEnumerable ist aber keine ICollection.

Es sieht zuerst so aus, als ob Sie die Feldzuordnungsfunktion verwenden können. Mit EF 1.1 ist dies jedoch nicht möglich, weil nur die Zuordnung zu skalaren Eigenschaften unterstützt wird. Dies soll sich im nächsten Release von EF Core ändern, in dem die Zuordnung zu Navigationseigenschaften zulässig sein wird. Als ich darauf eines Tages auf Twitter hinwies, ließ Arthur Vickers mich wissen, dass die Zuordnung zu IEnumerables tatsächlich möglich ist. Das war mir zu EF Core bisher entgangen. Ich kann also jetzt eine Sammlung vollständig kapseln und schützen und Benutzer meiner API so zwingen, eine Methode zum Ändern der Sammlung zu verwenden. Im folgenden Beispiel kann ich einem Buch bei jedem Ausleihvorgang neue BookLoan-Instanzen hinzufügen und auf diese Weise sicherstellen, dass der Ausleihzeitraum eingeschlossen wird:

private List<BookLoan> _bookLoans;
public IEnumerable<BookLoan> BookLoans {
  get { return _bookLoans; }
}
public void BookWasLoaned(int daysLoaned){
  _bookLoans.Add(new BookLoan(DateTime.Today, 14));
}

Dies ist eines der Muster zum Erreichen von Kapselung durch Nutzen der IEnumerable-Zuordnung. Ich empfehle, Arthurs Blogbeitrag (bit.ly/2fVzIfN) zu lesen, um weitere Details zu erfahren, z. B. zur Vorgehensweise ohne Verwendung eines Sicherungsfelds (ähnlich wie in meinem _bookLoans-Feld), zu den Optimierungsplänen sowie zu einigen Fallstricken, die beachtet werden sollten.

Unterstützung für datenbankspezifische Features. EF Core wurde so konzipiert, dass Anbieter auf einfachere Weise spezifische Features des Datenspeichers unterstützen können. Beispielsweise unterstützt der SQL Server-Anbieter für EF Core speicheroptimierte SQL Server-Tabellen für Anwendungen, in denen der Durchsatz außerordentlich hoch ist. Der SQL Server-Anbieter verfügt zum Angeben, dass eine Entität diesem speziellen Typ von Tabelle zugeordnet ist, über eine Erweiterungsmethode, die Sie beim Konfigurieren Ihres Modells mit der Fluent-API verwenden können:

modelBuilder.Entity<Book>().ForSqlServerIsMemoryOptimized();

Dies wirkt sich nicht nur darauf aus, wie Code First Tabellenerstellungsskripts generiert, sondern auch darauf, wie EF Befehle zum Übermitteln von Daten in die Datenbank mithilfe von Push generiert. Eine interessante Demo dazu können Sie im weiter oben erwähnen Channel 9-Video sehen, in dem Rowan Miller EF 1.1-Features vorführt.

Shay Rojansky, der den PostgreSQL-Anbieter für EF Core erstellt hat, hat einen Artikel dazu verfasst, wie er mit EF Core besondere Features von PosgreSQL (etwa Arraytypen) unterstützen kann. Sie finden diesen Artikel unter bit.ly/2focZKQ.

Einfacherer Zugriff auf Dienste

Wie bereits weiter oben anhand des EntityFinder-Diensts erläutert, besteht EF Core aus Hunderten von Diensten. Im Channel 9-Video zeigt Rowan, wie auf diese Dienste direkt in Ihrem Code zugegriffen werden kann und wie sie verwendet werden. Außerdem können Sie einen Dienst mit Ihrer eigenen Anpassung überschreiben. EF 1.1 vereinfacht diesen Vorgang durch eine einfache Ersetzungsmethode, die in OnConfiguring verwendet werden kann. Sie können einen Dienst durch einen anderen Dienst ersetzen, der von diesem Dienst erbt oder der die gleiche Schnittstelle implementiert. Es ist keine spezielle Liste der Dienste vorhanden. Es handelt sich nur um Klassen in den verschiedenen APIs von EntityFrameworkCore. Ein einfach zu verstehendes Beispiel ist das Erstellen einer Klasse, die von einer Datenbanktypzuordnung erbt (wie SqlLiteTypeMapper vom Sqlite-Anbieter), der eine neue Typzuordnungsregel hinzugefügt wird. Stellen Sie sicher. dass die Datenbank die Regel umwandeln kann. (Einige intelligentere Typumwandlungen werden in einer zukünftigen Version von EF Core enthalten sein.) Legen Sie anschließend in OnConfiguring die Ersetzungsregel fest:

optionsBuilder.ReplaceService<SqliteTypeMapper,MySqliteTypeMapper>();

Warum habe ich den EntityFinder-Dienst nicht ersetzt? Erstens: Ich mag seine Funktionsweise. Der zweite Grund besteht darin, dass es sich um eine generische Klasse handelt. Das Erstellen einer neuen Version einer solchen Klasse ist komplizierter, und ich habe diese Ausgabe erst einmal aufgeschoben. ReplaceService wurde zwar erstellt, um das Ersetzen interner Dienste zu vereinfachen. Sie müssen jedoch daran denken, dass sich die Interna von EF Core ändern können. Ihre Ersetzung kann sich daher im Lauf der Zeit ggf. als problematisch erweisen. Sie können diese auf einfache Weise identifizieren, weil sie sich in Namespaces befinden, die mit dem Wort „Internal“ enden. Microsoft sagt dazu Folgendes: „Wir vermeiden im Allgemeinen grundlegende Änderungen in Nicht-.Internal-Namespaces in Neben- und Patchreleases.“

Außerdem muss die Behebung eines Leistungsproblems (das damals einige Aufregung verursacht hat) erwähnt werden, das sich auf asynchrone Abfragen mithilfe der Include-Methode bezog. Dieses Problem wurde unmittelbar vor der Veröffentlichung von Version 1.0 erkannt. Es wurde schnell (siehe bit.ly/2faItD1, wenn Sie an den Einzelheiten interessiert sind) mit einer gemeldeten Leistungssteigerung von 70 Prozent behoben. Diese Problembehebung ist nun auch Bestandteil von Release 1.1.

Zusammenfassung

EF Core verfügt über zahlreiche anspruchsvolle Features. Sie müssen sich unbedingt bewusst sein, was in EF Core enthalten ist, was nicht enthalten ist, was bald enthalten sein wird und was niemals Bestandteil sein wird. Die EF Core-Dokumentation, in der die Beziehung zu EF6 beschrieben wird (bit.ly/2fxbVVj), stellt ebenfalls eine nützliche Ressource dar. Der Punkt ist folgender: Sie entscheiden, wann EF Core für Sie und Ihre Apps geeignet ist.

Für die meisten Arbeiten, die ich erledige, verfügt EF Core 1.1 über die benötigten APIs und Features. Als DDD-Praktikerin ist die Möglichkeit zum Kapseln von Sammlungen ein Gewinn für mich. Aber ich warte noch immer darauf, dass die komplexen Typzuordnungen verfügbar werden, damit ich Wertobjekte in meinen Modellen verwenden kann. Dieses Feature ist für das nächste Release von EF Core vorgesehen. Gefreut hat es mich neulich, als ich entdeckt habe, dass EF Core einen meiner Wünsche erfüllt hat: das Definieren eines schreibgeschützten (nicht nachverfolgenden) DbContext. Mir war entgangen, dass dieses Feature bereits in einem frühen Stadium hinzugefügt wurde und Bestandteil von Release 1.0 von EF Core war. Mehr zu diesem Thema finden Sie in meinem Blogbeitag unter bit.ly/2f75l8m.


Julie Lerman ist Microsoft MVP, .NET-Mentorin und Unternehmensberaterin. Sie lebt in den Bergen von Vermont. Sie hält bei User Groups und Konferenzen in der ganzen Welt Vorträge zum Thema Datenzugriff und anderen .NET-Themen. Julie Lerman führt unter thedatafarm.com/blog einen Blog. Sie ist die Autorin von „Programming Entity Framework“ sowie der Ausgaben „Code First“ und „DbContext“ (alle bei O’Reilly Media erschienen). Folgen Sie ihr auf Twitter: @julielerman, und sehen Sie sich ihre Pluralsight-Kurse unter juliel.me/PS-Videos an.

Unser Dank gilt dem folgenden technischen Experten bei Microsoft für die Durchsicht dieses Artikels: Rowan Miller


Diesen Artikel im MSDN Magazine-Forum diskutieren