Freigeben über


Datenpunkte

Verschieben vorhandener Projekte nach EF 5

Julie Lerman

 

Julie LermanIn Microsoft .NET Framework 4.5 wurde eine Anzahl von Änderungen und Verbesserungen an den Kern-Entity Framework-APIs vorgenommen. Die wichtigste Änderung betrifft die neue Art und Weise, wie in Entity Framework LINQ to Entities-Abfragen automatisch gespeichert werden, ohne dass es dabei zu Leistungseinbußen beim Übersetzen von Abfragen in SQL bei wiederholter Verwendung kommt. Dieses Feature wird als „automatisch kompilierte LINQ-Abfragen“ bezeichnet. Sie erfahren mehr darüber und über weitere Leistungsverbesserungen im Blogbeitrag des Teams „Vorschau: Leistungsverbesserungen in Entity Framework 5“ unter bit.ly/zlx21L. Ein Vorteil dieses Features besteht darin, dass es von der Entity Framework-API in .NET Framework 4.5 gesteuert wird. Folglich profitieren sogar .NET 4-Anwendungen, in denen Entity Framework verwendet wird, ohne Beeinträchtigung davon, wenn sie auf Computern mit installiertem .NET 4.5 ausgeführt werden.

Weitere nützliche, in die Kern-API integrierte neue Features erfordern von Ihnen etwas Programmierarbeit, einschließlich Support für Enumerationen, räumliche Datentypen und Tabellenwertfunktionen. Der Visual Studio 2012 Entity Data Model(EDM)-Designer verfügt auch über einige neue Features, einschließlich der Möglichkeit, unterschiedliche Ansichten des Modells zu erstellen.

Die meiste EF-bezogene Programmierarbeit führe ich heutzutage mit der DbContext-API durch. Sie wird zusammen mit den Code First-Features separat von .NET Framework bereitgestellt. Diese Features reflektieren das Konzept von Microsoft, an Entity Framework flexibler und häufiger Verbesserungen vorzunehmen. Sie befinden sich in einer einzigen Bibliothek, EntityFramework.dll, die Sie in Ihren Projekten über NuGet installieren können.

Um die Vorteile der Enumerationsunterstützung und der anderen Features zu nutzen, die EF in .NET Framework 4.5 hinzugefügt wurden, benötigen Sie die kompatible Version von EntityFramework.dll, EF 5. Die erste Version dieses Pakets hat die Versionsnummer 5.

Ich besitze viele Anwendungen, in denen EF 4.3.1 verwendet wird. Diese Version enthält in EF 4.3 eingeführte Migrationsunterstützung sowie ein paar kleinere Anpassungen, die kurz darauf hinzugefügt wurden. In diesem Artikel wird erläutert, wie eine mit EF 4.3.1 arbeitende Anwendung nach EF 5 verschoben wird, damit sie von der neuen Enumerationsunterstützung in .NET 4.5 profitiert. Die beschriebenen Schritte beziehen sich auch auf Projekte, in denen EF 4.1, 4.2 oder 4.3 verwendet wird.

Ich beginne mit einer einfachen Demowarelösung, in der ein Projekt für DomainClasses, ein anderes für DataLayer sowie eine Konsolenanwendung enthalten sind (siehe Abbildung 1).

The Existing Solution That Uses EF 4.3.1
Abbildung 1: Die vorhandene Lösung, in der EF 4.3.1 verwendet wird

Diese Lösung wurde in Visual Studio 2010 mithilfe von .NET Framework 4 und der EF 4.3.1-Version von EntityFramework.dll erstellt.

Das DomainClasses-Projekt verfügt über zwei Klassen, die in einer einzigen Datei zusammengefasst sind (siehe Abbildung 2), und verwendet im Beispielcode ein beliebtes Thema: Twitter. Die Klassen heißen Tweeter und Tweet.

Abbildung 2: Die ursprünglichen Domänenklassen

using System.ComponentModel.DataAnnotations;
namespace DataPointsDemo.DomainClasses
{
  public class Tweeter
  {
    public Tweeter()
    {
      Tweets = new List<Tweet>();
    }
    public int Id { get; set; }
    [Required]
    public string Name { get; set; }
    [MaxLength(10),Column("ExperienceCode")]
    public string Experience { get; set; }
    [MaxLength(30), MinLength(5)]
    public string UserName { get; set; }
    [RegularExpression(@"(\w[-._\w]*\w@\w[-._\w]*\w\.\w{2,3})")]
    public string Email { get; set; }
    public string Bio { get; set; }
    public DateTime CreateDate { get; set; }
    public byte[] Avatar { get; set; }
    public ICollection<Tweet> Tweets { get; set; }
    public string AliasPlusName
    { get { return Name + "(" + UserName + ")"; } }
  }
  public class Tweet
  {
    public int Id { get; set; }
    public DateTime CreateDate { get; set; }
    public string Content { get; set; }
    [Range(1, 5),Column("RatingCode")]
    public int Rating { get; set; }
    public Tweeter Alias { get; set; }
    public int AliasId { get; set; }
  }
}

In diesem Projekt werden Datenanmerkungen nicht nur zum Hinzufügen von Überprüfungen (wie RegularExpression) verwendet, sondern auch zum Definieren eines Teils der Konfiguration: MaxLength, MinLength und Column. Column gibt den Spaltennamen in der Datenbanktabelle an, dem die Felder „Experience“ und „Rating“ zugeordnet sind.

Alle drei Projekte verweisen auf EntityFramework.dll (Version 4.3.1). Normalerweise schließe ich EntityFramework.dll und alle Datenbankkenntnisse aus meinen Domänenklassen aus. Ich habe mich jedoch entschieden, sie zu Demonstrationszwecken in dieses Beispiel zu integrieren. Die Attribute MaxLength, MinLength und Column befinden sich im selben Namespace wie die Überprüfungen (System.ComponentModel.DataAnnotations), sie gehören jedoch zur EntityFramework-Assembly.

Die Domänenklassen enthalten zwei Eigenschaften, die die Verwendung von Enumerationen ans Herz legen: Tweeter.Experience verwendet eine Zeichenfolge als Wert, und Tweet.Rating verwendet einen numerischen Wert. Es liegt beim Entwickler, die Programmierung anhand dieser Klassen vorzunehmen, um sicherzustellen, dass den Benutzern die richtigen Werte zur Verfügung stehen. Warum keine Enumerationen? Weil das Kern-Entity Framework-API in .NET Framework 4 keine Enumerationen unterstützt. Und da es das am häufigsten geforderte Feature für Entity Framework war und nun Teil von .NET Framework 4.5 ist (und von Code First in EF 5 unterstützt wird), kann ich es verwenden. Aktualisieren wir also die Lösung.

Auch wenn ich meine Lösung in Visual Studio 2012 RC geöffnet habe, ist sie immer noch auf .NET 4 ausgerichtet. Als Erstes muss ich meine drei Projekte auf .NET 4.5 ausrichten. Dies kann ich im Fenster „Eigenschaften“ jedes Projekts durchführen (siehe Abbildung 3). Da dies für jedes Projekt einzeln gemacht werden muss, bietet es sich bei vielen Projekten an, ein Skript für die Projektdateien direkt auszuführen.

Changing a .NET Framework 4 Project to .NET Framework 4.5
Abbildung 3: Ändern eines .NET Framework 4-Projekts zu .NET Framework 4.5

Es ist wichtig, diesen Schritt vor der Aktualisierung auf EF 5 durchzuführen. Ich habe hierfür einiges Lehrgeld bezahlen müssen und möchte im Folgenden die Gründe erläutern.

Sobald die Projekte auf .NET Framework 4.5 ausgerichtet sind, können Sie eine Aktualisierung auf EF 5 durchführen. Da mehrere Projekte diese Assembly verwenden, sollten Sie die Pakete für die gesamte Lösung verwalten, anstatt ein Projekt nach dem anderen zu aktualisieren. Die Option „NuGet-Pakete verwalten“ steht im Projektmappen-Explorer im Kontextmenü der Lösung zur Verfügung. Mithilfe dieser Option wird die Benutzeroberfläche des Paket-Managers geöffnet. Wählen Sie auf der linken Seite „Updates“ aus. Wenn Sie eine aktuelle Version des Paket-Managers besitzen, wird im mittleren Bereich eine Dropdownliste mit den Optionen „Stable Only“ und „Include Prerelease“ angezeigt. Wenn Sie dies wie ich vor der offiziellen Veröffentlichung von .NET 4.5 und EF 5 machen, müssen Sie „Include Prerelease“ auswählen. Da in meiner bestimmten Lösung nur das EntityFramework-Paket aktualisiert werden muss, wird es angezeigt (siehe Abbildung 4). Falls Sie gerne in der Paket-Manager-Konsole arbeiten, können Sie „Install-Package EntityFramework –prerelease“ eingeben. Allerdings müssen Sie dies einzeln für jedes Projekt durchführen.

Finding the Entity Framework 5 Prerelease Update
Abbildung 4: Suchen nach dem Vorabupdate für Entity Framework 5

Im Assistenten werden Sie nach dem Auslösen der Paketaktualisierung gefragt, welche Projekte Sie aktualisieren möchten. Auch wenn in allen drei Projekten Entity Framework 4.3.1 verwendet wird, aktualisiere ich nur ConsoleApplication und DataLayer. Daher muss ich die Auswahl für DomainClasses aufheben. Am Statusfeld können Sie erkennen, welche Schritte gerade durchgeführt werden. Schließen Sie nach Abschluss des Updates den Paket-Manager.

Ein Paket, zwei DLLs

Die Aktualisierung auf EF 5 hat mehrere Auswirkungen auf die beiden Projekte. Als Erstes wurde die Version 4.3.1 von EntityFramework.dll durch die Version 5 ersetzt. Sie sollten dies für alle zu aktualisierenden Projekte überprüfen. Dies zeigt, warum es so wichtig ist, vor der Ausführung der Paketaktualisierung zu .NET Framework 4.5 zu wechseln. Das EF 5-Paket enthält zwei DLLs. Eine ist Version 5. Sie enthält alle DbContext-API- und Code First-Features und ist mit .NET 4.5 kompatibel. Die Version der anderen Datei ist 4.4. Diese bleibt kompatibel mit .NET 4. Durch das Hinzufügen dieser DLL zum Paket müssen nicht zwei separate NuGet-Pakete gepflegt werden. Also eine Sorge weniger. Nach der Veröffentlichung von EF 5 installieren Sie immer das gleiche EF 5-Pakte, wenn Sie DbContext- oder Code First-Support benötigen. Durch das Paket wird sichergestellt, dass in Ihrem Projekt die richtige Version installiert ist, ganz gleich, ob das Projekt in .NET 4 oder .NET 4.5 ist.

Als ich das Update auf EF zum ersten Mal durchführte, hatte ich meine Projekte vorher nicht auf .NET 4.5 aktualisiert. Die neuen Features wollten einfach nicht funktionieren, was mich sehr verwirrte. Dann stellte ich fest, dass ich Version 4.4 von EntityFramework.dll hatte, was mich noch mehr verwirrte. Schließlich durchsuchte ich die Paketdateien in der Lösung und stellte fest, dass ich zwei Pakete besaß. Dann verstand ich meinen Fehler.

Durch die EF 5-Aktualisierung wurde auch die app.config-Datei im Console-Projekt geändert und eine app.config-Datei im DataLayer-Projekt erstellt. Da in meiner ursprünglichen Lösung das Standardverhalten von Code First zum automatischen Ermitteln der relevanten Datenbank verwendet wurde, hatte ich in der Konfigurationsdatei keine Verbindungszeichenfolge und keine Verbindungsfactoryinformationen. Durch die Installation von EF 5 wurde dem <entityFramework>-Abschnitt der Datei der folgende Abschnitt hinzugefügt:

<defaultConnectionFactory
  type="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework">
  <parameters>
    <parameter
       value="Data Source=(localdb)\v11; Integrated Security=True;
              MultipleActiveResultSets=True" />
  </parameters>
</defaultConnectionFactory>

Zusätzlich wurde die app.config-Referenz auf die EF-Assembly aktualisiert, sodass sie die neue Versionsnummer widerspiegelt.

Projekte ohne Konfigurationsdatei erhalten eine neue app.config-Datei mit der Standardkonfiguration von EF 5. Das ist der Grund, warum das DataLayer-Projekt nach dem Update eine app.config-Datei enthält. Da ich in dem Projekt jedoch keine Konfigurationsdatei brauche, lösche ich die Datei einfach.

Was ist mit dem DomainClasses-Projekt?

Beim Aktualisieren habe ich das Projekt mit den Domänenklassen übersprungen. Ich brauchte EntityFramework.dll in der vorherigen Version meiner Lösung nur, um Zugriff auf die für EF spezifischen Datenanmerkungen zu erhalten. Diese wurden jetzt jedoch wie die anderen Datenanmerkungen in die .NET Framework 4.5-Assembly (System.ComponentModel.DataAnnotations.dll) verschoben. Ich muss also EF nicht mehr von dem Projekt referenzieren. Ich kann sogar den EntityFramework-Verweis aus dem Projekt deinstallieren. Anstatt die Benutzeroberfläche des Paket-Managers zu verwenden, öffne ich lieber das Paket-Manager-Konsolenfenster, um die Ausrichtung auf das DomainClasses-Projekt zu überprüfen. Dann gebe ich „uninstall-package entityframework“ ein, um das Paket aus dem Projekt zu entfernen.

Es muss aber noch ein weiterer Schritt durchgeführt werden. Beim Öffnen der Datei mit den Klassen wird eine Compilerwarnung für die drei Datenanmerkungen im Mittelpunkt meiner Betrachtungen angezeigt. Ursprünglich befanden sie sich als Teil von EntityFramework.dll im System.ComponentModel.DataAnnotations-Namespace. In der .NET-Assembly, wo sie sich jetzt befinden, wurden sie jedoch in einen Sub-Namespace verschoben. Folglich muss ich am Anfang der Codedatei eine weitere using-Anweisung hinzufügen:

using System.ComponentModel.DataAnnotations.Schema;

Damit ist der Compiler happy, und ich bin es auch, weil ich die Abhängigkeit von Entity Framework in Klassen, die nichts mit Datenzugriff zu tun haben, entfernt habe. Persönlich mag ich weiterhin meinen Domänenklassen keine Attribute hinzufügen, die das Datenbankschema definieren. Stattdessen verwende ich für diese Aufgaben lieber Entity Framework-Fluent-API-Konfigurationen. In kleineren Projekten lassen sich Datenanmerkungen jedoch praktisch und schnell einsetzen.

Unterschiedliche Versionen

Sie haben die Möglichkeit, EF 4.3.x in einem Projekt zu installieren, das auf .NET Framework 4.5 ausgerichtet ist. Wenn Sie dies tun (absichtlich oder versehentlich), wird in der IDE eine Textdatei angezeigt, die bekannte Probleme beim Verwenden von EF 4.x in einem .NET 4.5-Projekt auflistet und die Installation von EF 5 empfiehlt. Sobald EF 5 stabil und zum Standardpaket wird, sollte die Wahrscheinlichkeit, dass den Entwicklern dieser Fehler unterläuft, verschwinden.

Wechseln zu Enumerationen

Wenn dies alles erfolgt ist, kann ich meine Domänenklassen ändern, um die unschöne Problemumgehung zu entfernen und Enumerationen für die Rating- und Experience-Eigenschaften zu verwenden. Sehen Sie sich die beiden neuen Enumerationen an. Beachten Sie, dass ich für die eine Enumeration Werte angegeben habe, für die andere jedoch nicht. Dies habe ich gemacht, damit Sie nachverfolgen können, wie beide Szenarien von EF gehandhabt werden.

public enum TweetRating
{
  Suxorz = 0,
  WorksForMe = 1,
  WatchOutAPlusK = 2
}
public enum TwitterExperience
{
  Newbie, BeenAround, Ninja
}

Nach Bearbeitung der Enumerationen kann ich die Eigenschaften folgendermaßen ändern:

[Column("ExperienceCode")]
public TwitterExperience Experience { get; set; }
[Column("RatingCode")]
public TweetRating Rating { get; set; }

Ich brauche keine Attribute mehr, um den Bereich oder die Länge der Eigenschaft anzugeben. Diese Änderung führe ich durch, ohne mögliche vorhandene Daten in meiner Demonstrationsdatenbank zu berücksichtigen. Wenn Sie eine solche Änderung an einer Anwendung durchführen, die sich in der Produktion befindet, müssen Sie die Datenänderung vorab vorbereiten. Ich ändere die Bedeutung von Experience in der Datenbank vollständig und habe auch die Tweetbewertung zufällig von 1-5 auf 0-2 geändert.

Nach der Verwendung von Code First-Migrationen zum Aktualisieren der Datenbank wurde die Tweeter.ExperienceCode-Spalte von einem nvarchar-Datentyp in einen int-Typ geändert. C# und Visual Basic interpretieren die Enumeration standardmäßig als ganze Zahl und beginnen die Enumeration mit 0. Deshalb ordnet Code First die Enumerationswerte einem int-Datentyp in der Datenbank zu. Sie können die Enumeration einem anderen Typ zuordnen (innerhalb der Grenzen von C#- und Visual Basic-Enumerationen), was von Code First berücksichtigt wird. Wenn Sie beispielsweise eine Enumeration als „long“ definieren, entsprechen die resultierenden Eigenschaften einem bigint-Datentyp. Standardmäßig beginnt eine ganze Zahl immer mit 0. In meinem Beispiel wird Newbie in der Datenbank durch 0 dargestellt, BeenAround durch 1 und Ninja durch 2. Wenn Sie in der Zukunft möglicherweise beliebige Enumerationsmitglieder entfernen, neu anordnen oder neue nicht am Ende hinzufügen möchten, sollten Sie explizite Werte wie in der TweetRating-Enumeration verwenden. Dadurch können Sie die Enumeration einfacher ändern, ohne dabei diese Werte versehentlich zu ändern. Denken Sie daran, dass nur der numerische Wert in der Datenbank gespeichert wird. Falls Sie den Wert in der Enumeration also tatsächlich einmal ändern, ändern Sie die Bedeutung Ihrer Daten, was, wie es der C#-Guru Jon Skeet ausdrückt, fast immer „etwas Schlechtes“ ist.

Abbildung 5 zeigt Code, durch den eine neue Tweeter-Instanz zusammen mit einem Tweet erstellt wird. Beide verwenden die Enumerationen. Nachdem Sie die Daten gespeichert haben, werden in der Datenbank die Werte von ExperienceCode gleich 1 und Rating gleich 2 angezeigt.

Abbildung 5: Erstellen eines neuen Diagramms für einen Tweeter und einen Tweet

var alias = new Tweeter
  {
    Name = "Julie",
    UserName = "Julie",
    Bio = "Mom of Giantpuppy",
    CreateDate = DateTime.Now,
    Experience = TwitterExperience.BeenAround,
    Tweets = new List<Tweet>{new Tweet
               {
                 Content = "Oh how I love that Giantpuppy",
                 CreateDate = DateTime.Now,
                 Rating = TweetRating.WatchOutAPlusK
               }}
  };

Sie können diese Enumerationen in Abfragen verwenden. Der enum-Wert wird in SQL in den int-Wert umgewandelt, und die zurückgegebenen int-Werte werden wieder zurück in enum-Werte umgewandelt. Im Folgenden sehen Sie eine LINQ-Abfrage, die im Where-Prädikat eine Enumeration verwendet:

context.Tweeters.Where(t => t.Experience == 
  TwitterExperience.Ninja)

In der resultierenden T-SQL lautet der Wert des Where-Prädikats 2.

Reibungsloseres Verschieben nach EF 5

Ich habe gehört, dass sich einige Entwickler schon darauf freuen, ihre vorhandenen Entity Framework-Lösungen nach EF 5 zu übertragen, um vom Support für Enumerationen und räumliche Daten zu profitieren. Die Übertragung von Projekten von EF 4 nach EF 5 ist nicht unbedingt hoch kompliziert, der Weg war aber holprig genug, um bei den ersten Versuchen bei mir Unmut zu erzeugen. Ich hoffe, dass Ihnen dieser Artikel beim Verschieben Unterstützung bietet.

Mir gefällt, dass im einfachen NuGet-Paket für Code First- und DbContext-Support kompatible DLLs sowohl für .NET 4 als auch für .NET 4.5 enthalten sind. Selbst wenn ich EDMX verwende, kann ich alle neuen Projekte mit DbContext starten. Deshalb basieren 100 Prozent meiner Projekte jetzt auf dem Entity Framework NuGet-Paket.

EF 4-Anwendungen, die auf Computern mit installiertem .NET Framework 4.5 ausgeführt werden, profitieren von den Leistungsverbesserungen. Selbst wenn Sie noch nicht zu Visual Studio 2012 wechseln, können Ihre Benutzer von den Verbesserungen am Entity Framework-Kern in .NET Framework 4.5 profitieren.

Julie Lerman ist Microsoft MVP, .NET-Mentor und Unternehmensberaterin und 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 Microsoft .NET-Themen. Julie Lerman führt unter thedatafarm.com/blog einen Blog. Sie ist die Verfasserin von „Programming Entity Framework“ (2010) sowie der Ausgaben „Code First“ (2011) und „DbContext“ (2012). Alle Ausgaben sind im Verlag O’Reilly Media erschienen. Folgen Sie ihr auf Twitter unter twitter.com/julielerman.

Unser Dank gilt dem folgenden technischen Experten für die Durchsicht dieses Artikels: Arthur Vickers