Model-Based KonventionenModel-Based Conventions

Hinweis

Nur EF6 und höher: Die Features, APIs usw., die auf dieser Seite erläutert werden, wurden in Entity Framework 6 eingeführt.EF6 Onwards Only - The features, APIs, etc. discussed in this page were introduced in Entity Framework 6. Wenn Sie eine frühere Version verwenden, gelten manche Informationen nicht.If you are using an earlier version, some or all of the information does not apply.

Modellbasierte Konventionen sind eine erweiterte Methode der Modell Konfiguration, die auf der Konvention basiert.Model based conventions are an advanced method of convention based model configuration. In den meisten Szenarien sollte die API für die benutzerdefinierte Code First Konvention in dbmodelbuilder verwendet werden.For most scenarios the Custom Code First Convention API on DbModelBuilder should be used. Vor der Verwendung von modellbasierten Konventionen wird ein Verständnis der dbmodelbuilder-API für Konventionen empfohlen.An understanding of the DbModelBuilder API for conventions is recommended before using model based conventions.

Modellbasierte Konventionen ermöglichen die Erstellung von Konventionen, die sich auf Eigenschaften und Tabellen auswirken, die nicht über Standard Konventionen konfiguriert werden können.Model based conventions allow the creation of conventions that affect properties and tables which are not configurable through standard conventions. Beispiele hierfür sind diskriminatorspalten in Tabelle pro Hierarchie Modellen und unabhängigen Assoziations Spalten.Examples of these are discriminator columns in table per hierarchy models and Independent Association columns.

Erstellen einer KonventionCreating a Convention

Der erste Schritt beim Erstellen einer modellbasierten Konvention ist die Entscheidung, wann in der Pipeline die Konvention auf das Modell angewendet werden muss.The first step in creating a model based convention is choosing when in the pipeline the convention needs to be applied to the model. Es gibt zwei Arten von Modell Konventionen: konzeptionell (C-Space) und Speicher (S-Space).There are two types of model conventions, Conceptual (C-Space) and Store (S-Space). Eine C-Space-Konvention wird auf das Modell angewendet, das von der Anwendung erstellt wird, wohingegen eine S-Space-Konvention auf die Version des Modells angewendet wird, die die Datenbank darstellt, und steuert, wie automatisch generierte Spalten benannt werden.A C-Space convention is applied to the model that the application builds, whereas an S-Space convention is applied to the version of the model that represents the database and controls things such as how automatically-generated columns are named.

Eine Modell Konvention ist eine Klasse, die sich entweder von ikonzeptionalmodelconvention oder istoremodelconvention erstreckt.A model convention is a class that extends from either IConceptualModelConvention or IStoreModelConvention. Diese Schnittstellen akzeptieren beide einen generischen Typ, der vom Typ "MetadataItem" sein kann, der zum Filtern des Datentyps verwendet wird, für den die Konvention gilt.These interfaces both accept a generic type that can be of type MetadataItem which is used to filter the data type that the convention applies to.

Hinzufügen einer KonventionAdding a Convention

Modell Konventionen werden auf die gleiche Weise wie reguläre Konventionen-Klassen hinzugefügt.Model conventions are added in the same way as regular conventions classes. Fügen Sie in der onmodelcreating -Methode der Liste der Konventionen für ein Modell die Konvention hinzu.In the OnModelCreating method, add the convention to the list of conventions for a model.

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 mit der Konventionen. AddBefore- <> Methode oder der Conventions. AddAfter-Methode in Relation zu einer anderen Konvention hinzugefügt werden <> .A convention can also be added in relation to another convention using the Conventions.AddBefore<> or Conventions.AddAfter<> methods. Weitere Informationen zu den Konventionen, die Entity Framework angewendet wird, finden Sie im Abschnitt "Hinweise".For more information about the conventions that Entity Framework applies see the notes section.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.AddAfter<IdKeyDiscoveryConvention>(new MyModelBasedConvention());
}

Beispiel: diskriminatormodellkonventionExample: Discriminator Model Convention

Das Umbenennen von von EF generierten Spalten ist ein Beispiel für etwas, das Sie mit den anderen Konventionen-APIs nicht ausführen können.Renaming columns generated by EF is an example of something that you can’t do with the other conventions APIs. Dies ist eine Situation, in der die Verwendung von Modell Konventionen Ihre einzige Option ist.This is a situation where using model conventions is your only option.

Ein Beispiel für die Verwendung einer modellbasierten Konvention zum Konfigurieren generierter Spalten ist die Anpassung der Art und Weise, wie diskriminatorspalten benannt werden.An example of how to use a model based convention to configure generated columns is customizing the way discriminator columns are named. Im folgenden finden Sie ein Beispiel für eine einfache modellbasierte Konvention, die jede Spalte im Modell mit dem Namen "Diskriminator" in "EntityType" umbenennt.Below is an example of a simple model based convention that renames every column in the model named “Discriminator” to “EntityType”. Dies schließt Spalten ein, die der Entwickler einfach als "Diskriminator" bezeichnet.This includes columns that the developer simply named “Discriminator”. Da es sich bei der Spalte "Diskriminator" um eine generierte Spalte handelt, muss diese im Bereich von S ausgeführt werden.Since the “Discriminator” column is a generated column this needs to run in S-Space.

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-Umbenennungs KonventionExample: General IA Renaming Convention

Ein weiteres komplizierteres Beispiel für modellbasierte Konventionen in Aktion besteht darin, die Art und Weise zu konfigurieren, in der unabhängige Zuordnungen (IAS) benannt werden.Another more complicated example of model based conventions in action is to configure the way that Independent Associations (IAs) are named. Dies ist eine Situation, in der Modell Konventionen zutreffen, da IAS von EF generiert wird und nicht im Modell vorhanden ist, auf das die dbmodelbuilder-API zugreifen kann.This is a situation where Model conventions are applicable because IAs are generated by EF and aren’t present in the model that the DbModelBuilder API can access.

Wenn EF eine IA generiert, erstellt es eine Spalte mit dem Namen EntityType_KeyName.When EF generates an IA, it creates a column named EntityType_KeyName. Beispielsweise würde für eine Zuordnung mit dem Namen Customer und einer Schlüssel Spalte mit dem Namen CustomerID eine Spalte mit dem Namen Customer_CustomerId generiert werden.For example, for an association named Customer with a key column named CustomerId it would generate a column named Customer_CustomerId. In der folgenden Konvention wird das _ Zeichen "" aus dem für die IA generierten Spaltennamen entfernt.The following convention strips the ‘_’ character out of the column name that is generated for the IA.

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 KonventionenExtending Existing Conventions

Wenn Sie eine Konvention schreiben müssen, die einer der Konventionen ähnelt, die Entity Framework bereits auf Ihr Modell angewendet haben, können Sie diese Konvention immer erweitern, um zu vermeiden, dass Sie von Grund auf neu geschrieben werden muss.If you need to write a convention that is similar to one of the conventions that Entity Framework already applies to your model you can always extend that convention to avoid having to rewrite it from scratch. Ein Beispiel hierfür besteht darin, die vorhandene ID-abgleichskonvention durch eine benutzerdefinierte zu ersetzen.An example of this is to replace the existing Id matching convention with a custom one. Ein zusätzlicher Vorteil beim Überschreiben der Schlüssel Konvention besteht darin, dass die überschriebene Methode nur aufgerufen wird, wenn kein Schlüssel bereits erkannt oder explizit konfiguriert wurde.An added benefit to overriding the key convention is that the overridden method will get called only if there is no key already detected or explicitly configured. Eine Liste der Konventionen, die von Entity Framework verwendet werden, finden Sie hier: http://msdn.microsoft.com/library/system.data.entity.modelconfiguration.conventions.aspx .A list of conventions that used by Entity Framework is available here: 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;
    }
}

Anschließend müssen wir unsere neue Konvention vor der vorhandenen Schlüssel Konvention hinzufügen.We then need to add our new convention before the existing key convention. Nachdem wir customkeydiscoveryconvention hinzugefügt haben, können wir idkeydiscoveryconvention entfernen.After we add the CustomKeyDiscoveryConvention, we can remove the IdKeyDiscoveryConvention. Wenn wir die vorhandene idkeydiscoveryconvention nicht entfernt haben, hat diese Konvention weiterhin Vorrang vor der ID-Ermittlungs Konvention, da Sie zuerst ausgeführt wird. Wenn jedoch keine "Key"-Eigenschaft gefunden wird, wird die "ID"-Konvention ausgeführt.If we didn’t remove the existing IdKeyDiscoveryConvention this convention would still take precedence over the Id discovery convention since it is run first, but in the case where no “key” property is found, the “id” convention will run. Dieses Verhalten wird angezeigt, weil bei jeder Konvention das Modell wie in der vorherigen Konvention aktualisiert angezeigt wird (anstatt sie unabhängig voneinander zu betreiben), sodass eine vorherige Konvention z. b. einen Spaltennamen so aktualisiert hat, dass Sie etwas, das für Ihre benutzerdefinierte Konvention relevant ist (wenn der Name nicht von Interesse war), auf diese Spalte angewendet wird.We see this behavior because each convention sees the model as updated by the previous convention (rather than operating on it independently and all being combined together) so that if for example, a previous convention updated a column name to match something of interest to your custom convention (when before that the name was not of interest) then it will apply to that column.

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>();
    }
}

NotizenNotes

Eine Liste der Konventionen, die zurzeit von Entity Framework angewendet werden, finden Sie in der MSDN-Dokumentation unter: http://msdn.microsoft.com/library/system.data.entity.modelconfiguration.conventions.aspx .A list of conventions that are currently applied by Entity Framework is available in the MSDN documentation here: http://msdn.microsoft.com/library/system.data.entity.modelconfiguration.conventions.aspx. Diese Liste wird direkt aus dem Quellcode abgerufen.This list is pulled directly from our source code. 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.The source code for Entity Framework 6 is available on GitHub and many of the conventions used by Entity Framework are good starting points for custom model based conventions.