Ein Blick auf das Entity Framework 4
Angeregt durch ein aktuelles Projekt, musste ich mir das Entity Framework 4 (Microsofts OR-Mapper) anschauen. Bisher hatte ich es vermieden, da ich der Meinung war, dass ich die nötigen Mappings nur über den Designer mit viel Magie und wildem herumgeklicke herstellen kann. Allerdings halte ich es für wichtig, dass die Entities, die ich in meinen Projekten benötige, nicht autogeneriert sind, bzw. nicht vom OR-Mapper generiert werden, da dadurch unnötige Abhängigkeiten zum OR-Mapper entstehen oder unnötige Objekt-Mappings gemacht werden müssen.
Üblicherweise halte ich meine Entities in einem Projekt, das von allen anderen Projekten referenziert wird, die mit diesen Entities arbeiten. Mit NHibernate ist das auch problemlos möglich.
BTW: Ich bin ein großer Fan von NHibernate und nutze diesen OR-Mapper bisher in fast jedem großen Projekt.
Ich möchte also meine Entities wie folgt aufbauen:
public class Customer : EntityBase
{
[StringLength(150)]
[Required]
public string Name { get; set; }
[StringLength(100)]
[Required]
public string Street { get; set; }
[StringLength(5)]
[Required]
[RegularExpression("^[0-9]{4,5}$")]
public string Postalcode { get; set; }
}
EntityBase ist eine Basisklasse, welche die Id bereitstellt, Equals überschreibt, etc. Die hier sichtbaren Attribute stammen von den DataAnnotations und werden zur Validierung genutzt.
Würde ich jetzt das EF wie gewohnt einsetzen, müsste ich z. B. per AutoMapper von den generierten Entities auf meine Mappen. Das möchte ich nicht, bzw. müsste es mit NHibernate auch nicht tun.
DbContext
Nun war es heute René Leupold der mir mit seinem Blog http://databinding.net den entscheidenden Tipp für den DbContext gab. Mit dem DbContext ist es möglich das Entity Framework ähnlich wie NHibernate zu verwenden.
Hilfreich ist auch die Artikelserie “Using DbContext in EF 4.1” im ADO.NET Team Blog
Der DbContext ist ab EF 4.1 verfügbar. Ich selber habe mir für diese Beispiele die EntityFramework.dll 4.2.0.0 per NuGet referenziert.
Das Mapping
Was wir zusätzlich benötigen ist ein Mapping, das hier per Fluent API per C# gesetzt wird:
internal class CustomerMapping : EntityTypeConfiguration<Customer>
{
public CustomerMapping()
{
Property(x => x.Name)
.HasMaxLength(200)
.IsVariableLength()
.IsUnicode()
.IsOptional();
Property(x => x.Postalcode)
.HasMaxLength(30)
.IsVariableLength()
.IsUnicode()
.IsOptional();
}
}
Genutzt wird die Konfiguration dann im DbContext:
public class DataContext : DbContext
{
public IDbSet<Customer> Customers { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Configurations.Add(new CustomerConfig());
}
}
Die Ähnlichkeit mit NHibernate ist an dieser Stelle eindeutig und ich habe meine gewünschte Trennung zwischen den Entities und dem OR-Mapper.
Die Connection
Interessant ist, dass die Verbindung zur Datenbank über den Constructor der Basisklasse DbContext gesetzt werden kann oder aber per Konvention:
<connectionStrings>
<add name="DataContext"
providerName="System.Data.SqlClient"
connectionString="Data Source=[…]" />
</connectionStrings>
Der Name des ConnectionStrings muss einfach so heißen wie der entsprechende DbContext
Benutzen
Wenn die DB schon existiert ist das im Prinzip auch schon alles um mit den Daten zu arbeiten:
[Test]
public void SetAndLoadCustomerFromDataBase()
{
IEnumerable<Customer> customers;
using (var context = new DataContext())
{
context.Customers.Add(new Customer
{
Id = Guid.NewGuid(),
Name = "Hallo Welt",
Street = "Hallo Street 2",
Postalcode = "12345"
});
context.SaveChanges();
}
using (var context = new DataContext())
{
customers = context.Customers.Select(c => c).ToList();
}
Assert.That(customers.Count(), Is.GreaterThan(0));
}
Das Mapping wird erzeugt, wenn das erste mal der DataContext instanziert wird. Es wird relativ viel mit Lazy<T> gearbeitet, so dass das Debugging der ergebnislisten nicht immer ganz einfach ist.
Demo
Eine Demo werde ich in den nächsten Tagen hier anhängen. Die vorhandenen Projekte muss ich erst noch anonymisieren.
Fazit
Mit dem DbContext scheint das EntityFramework doch noch ein ganz passables Werkzeug und eine ernstzunehmende Alternative zum NHibernate zu sein.