Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Hinweis
Nur EF6 und weiter – Die Funktionen, APIs und mehr, die auf dieser Seite besprochen werden, wurden in Entity Framework 6 eingeführt. Wenn Sie eine frühere Version verwenden, gelten einige oder alle Informationen nicht.
Modellbasierte Konventionen sind eine erweiterte Methode der konventionsbasierten Modellkonfiguration. In den meisten Szenarien sollte die Custom Code First Convention API von DbModelBuilder verwendet werden. Ein Verständnis der DbModelBuilder-API für Konventionen wird empfohlen, bevor modellbasierte Konventionen verwendet werden.
Modellbasierte Konventionen ermöglichen das Erstellen von Konventionen, die sich auf Eigenschaften und Tabellen auswirken, die nicht über Standardkonventionen konfigurierbar sind. Beispiele hierfür sind Diskriminatorspalten in dem Tabellen-pro-Hierarchiemodell und unabhängige Assoziationsspalten.
Erstellen einer Konvention
Der erste Schritt beim Erstellen einer modellbasierten Konvention ist die Wahl, wann die Konvention in der Pipeline auf das Modell angewendet werden muss. Es gibt zwei Arten von Modellkonventionen, Konzept (C-Space) und Store (S-Space). Eine C-Space-Konvention wird auf das Modell angewendet, das von der Anwendung erstellt wird, während eine S-Space-Konvention auf die Version des Modells angewendet wird, die die Datenbank darstellt, und steuert Dinge, z. B. wie automatisch generierte Spalten benannt werden.
Eine Modellkonvention ist eine Klasse, die sich von IConceptualModelConvention oder IStoreModelConvention erstreckt. Beide dieser Schnittstellen akzeptieren einen generischen Typ, der vom Typ "MetadataItem" ist und verwendet wird, um den Datentyp zu filtern, auf den sich die Konvention bezieht.
Hinzufügen einer Konvention
Modellkonventionen werden auf die gleiche Weise hinzugefügt wie normale Konventionsklassen. Fügen Sie in der OnModelCreating-Methode der Liste der Konventionen für ein Modell die Konvention hinzu.
using System.Data.Entity;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
public class BlogContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Add<MyModelBasedConvention>();
}
}
Eine Konvention kann auch in Bezug auf eine andere Konvention mithilfe der Methoden Conventions.AddBefore<> oder Conventions.AddAfter<> hinzugefügt werden. Weitere Informationen zu den Konventionen, die Entity Framework betrifft, finden Sie im Abschnitt "Hinweise".
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.AddAfter<IdKeyDiscoveryConvention>(new MyModelBasedConvention());
}
Beispiel: Diskriminator-Modellkonvention
Das Umbenennen von Spalten, die von EF generiert werden, ist ein Beispiel für etwas, das Sie nicht mit den anderen Konventionen-APIs tun können. Dies ist eine Situation, in der die Verwendung von Modellkonventionen Ihre einzige Option ist.
Ein Beispiel für die Verwendung einer modellbasierten Konvention zum Konfigurieren generierter Spalten ist das Anpassen der Art und Weise, wie Diskriminatorspalten benannt werden. Nachfolgend finden Sie ein Beispiel für eine einfache modellbasierte Konvention, die jede Spalte im Modell namens "Diskriminator" in "EntityType" umbenennt. Dazu gehören Spalten, die der Entwickler einfach "Diskriminator" genannt hat. Da die Spalte "Diskriminator" eine generierte Spalte ist, muss dies in S-Space ausgeführt werden.
using System.Data.Entity;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
class DiscriminatorRenamingConvention : IStoreModelConvention<EdmProperty>
{
public void Apply(EdmProperty property, DbModel model)
{
if (property.Name == "Discriminator")
{
property.Name = "EntityType";
}
}
}
Beispiel: Allgemeine IA-Umbenennungskonvention
Ein weiteres komplizierteres Beispiel für modellbasierte Konventionen im Einsatz besteht darin, die Art und Weise zu konfigurieren, wie unabhängige Assoziationen (Independent Associations, IAs) benannt werden. Dies ist eine Situation, in der Modellkonventionen anwendbar sind, da IAs von EF generiert werden und nicht im Modell vorhanden sind, auf das die DbModelBuilder-API zugreifen kann.
Wenn EF eine IA generiert, wird eine Spalte mit dem Namen EntityType_KeyName erstellt. Zum Beispiel wird bei einer Zuordnung namens Kunde mit einer Schlüsselsäule namens KundenId eine Spalte namens Kunde_KundenId erzeugt. Die folgende Konvention entfernt das Zeichen "_" aus dem Spaltennamen, der für die IA generiert wird.
using System.Data.Entity;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
// Provides a convention for fixing the independent association (IA) foreign key column names.
public class ForeignKeyNamingConvention : IStoreModelConvention<AssociationType>
{
public void Apply(AssociationType association, DbModel model)
{
// Identify ForeignKey properties (including IAs)
if (association.IsForeignKey)
{
// rename FK columns
var constraint = association.Constraint;
if (DoPropertiesHaveDefaultNames(constraint.FromProperties, constraint.ToRole.Name, constraint.ToProperties))
{
NormalizeForeignKeyProperties(constraint.FromProperties);
}
if (DoPropertiesHaveDefaultNames(constraint.ToProperties, constraint.FromRole.Name, constraint.FromProperties))
{
NormalizeForeignKeyProperties(constraint.ToProperties);
}
}
}
private bool DoPropertiesHaveDefaultNames(ReadOnlyMetadataCollection<EdmProperty> properties, string roleName, ReadOnlyMetadataCollection<EdmProperty> otherEndProperties)
{
if (properties.Count != otherEndProperties.Count)
{
return false;
}
for (int i = 0; i < properties.Count; ++i)
{
if (!properties[i].Name.EndsWith("_" + otherEndProperties[i].Name))
{
return false;
}
}
return true;
}
private void NormalizeForeignKeyProperties(ReadOnlyMetadataCollection<EdmProperty> properties)
{
for (int i = 0; i < properties.Count; ++i)
{
int underscoreIndex = properties[i].Name.IndexOf('_');
if (underscoreIndex > 0)
{
properties[i].Name = properties[i].Name.Remove(underscoreIndex, 1);
}
}
}
}
Erweitern vorhandener Konventionen
Wenn Sie eine Konvention schreiben müssen, die einer der Konventionen ähnelt, die Entity Framework bereits auf Ihr Modell angewendet hat, können Sie diese Konvention jederzeit erweitern, um zu vermeiden, dass sie von Grund auf neu geschrieben werden muss. Ein Beispiel hierfür ist das Ersetzen der vorhandenen ID-Abgleichskonvention durch eine benutzerdefinierte. Ein zusätzlicher Vorteil beim Überschreiben der Schlüsselkonvention besteht darin, dass die überschriebene Methode nur aufgerufen wird, wenn kein bereits erkannter oder explizit konfigurierter Schlüssel vorhanden ist. Eine Liste der Konventionen, die von Entity Framework verwendet werden, finden Sie hier: http://msdn.microsoft.com/library/system.data.entity.modelconfiguration.conventions.aspx.
using System.Data.Entity;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.Entity.Infrastructure;
using System.Data.Entity.ModelConfiguration.Conventions;
using System.Linq;
// Convention to detect primary key properties.
// Recognized naming patterns in order of precedence are:
// 1. 'Key'
// 2. [type name]Key
// Primary key detection is case insensitive.
public class CustomKeyDiscoveryConvention : KeyDiscoveryConvention
{
private const string Id = "Key";
protected override IEnumerable<EdmProperty> MatchKeyProperty(
EntityType entityType, IEnumerable<EdmProperty> primitiveProperties)
{
Debug.Assert(entityType != null);
Debug.Assert(primitiveProperties != null);
var matches = primitiveProperties
.Where(p => Id.Equals(p.Name, StringComparison.OrdinalIgnoreCase));
if (!matches.Any())
{
matches = primitiveProperties
.Where(p => (entityType.Name + Id).Equals(p.Name, StringComparison.OrdinalIgnoreCase));
}
// If the number of matches is more than one, then multiple properties matched differing only by
// case--for example, "Key" and "key".
if (matches.Count() > 1)
{
throw new InvalidOperationException("Multiple properties match the key convention");
}
return matches;
}
}
Dann müssen wir unsere neue Konvention vor der bestehenden Schlüsselkonvention hinzufügen. Nachdem wir die CustomKeyDiscoveryConvention hinzugefügt haben, können wir die IdKeyDiscoveryConvention entfernen. Wenn wir die vorhandene IdKeyDiscoveryConvention-Konvention nicht entfernt haben, hat diese Konvention weiterhin Vorrang vor der Id-Ermittlungskonvention, da sie zuerst ausgeführt wird, aber wenn keine "key"-Eigenschaft gefunden wird, wird die "id"-Konvention ausgeführt. Dieses Verhalten entsteht, weil jedes Übereinkommen das Modell als von der vorherigen Konvention aktualisiert betrachtet (anstatt es unabhängig davon zu bearbeiten und alle zusammenzuführen). Wenn beispielsweise eine vorherige Konvention einen Spaltennamen so aktualisiert, dass er zu Ihrer benutzerdefinierten Konvention passt (während zuvor der Name nicht von Interesse war), dann wird diese Änderung auf diese Spalte angewendet.
public class BlogContext : DbContext
{
public DbSet<Post> Posts { get; set; }
public DbSet<Comment> Comments { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.AddBefore<IdKeyDiscoveryConvention>(new CustomKeyDiscoveryConvention());
modelBuilder.Conventions.Remove<IdKeyDiscoveryConvention>();
}
}
Hinweise
Eine Liste der Konventionen, die derzeit von Entity Framework angewendet werden, finden Sie in der MSDN-Dokumentation hier: http://msdn.microsoft.com/library/system.data.entity.modelconfiguration.conventions.aspx. Diese Liste wird direkt aus unserem Quellcode abgerufen. Der Quellcode für Entity Framework 6 ist auf GitHub verfügbar, und viele der von Entity Framework verwendeten Konventionen sind gute Ausgangspunkte für benutzerdefinierte modellbasierte Konventionen.