Code First Data Annotations

Hinweis

Nur EF4.1 und höher: Die auf dieser Seite erläuterten Features, APIs usw. wurden in Entity Framework 4.1 eingeführt. Wenn du eine frühere Version verwendest, gelten manche oder alle Informationen nicht.

Der Inhalt auf dieser Seite wurde von einem Artikel übernommen, der ursprünglich von Julie Lerman (<http://thedatafarm.com>) geschrieben wurde.

Mit Entity Framework Code First können Sie Ihre eigenen Domänenklassen zum Darstellen des Modells verwenden, mit dem EF Abfragen, Änderungsnachverfolgung und Aktualisierungsfunktionen ausführt. Code First nutzt ein Programmiermuster, das als „Konvention vor Konfiguration“ bezeichnet wird. Code First geht davon aus, dass Ihre Klassen den Konventionen von Entity Framework folgen und findet in diesem Fall automatisch heraus, wie der Auftrag ausgeführt werden soll. Wenn Ihre Klassen diese Konventionen jedoch nicht einhalten, haben Sie die Möglichkeit, Ihren Klassen Konfigurationen hinzuzufügen, um die erforderlichen Informationen für EF bereitzustellen.

Code First bietet Ihnen zwei Möglichkeiten, diese Konfigurationen ihren Klassen hinzuzufügen. Eine ist die Verwendung einfacher Attribute namens DataAnnotations, und bei der zweiten wird die Fluent-API von Code First verwendet, die Ihnen eine Möglichkeit bietet, Konfigurationen im Code imperativ zu beschreiben.

Dieser Artikel konzentriert sich auf die Verwendung von DataAnnotations (im System.ComponentModel.DataAnnotations-Namespace), um Ihre Klassen zu konfigurieren, wobei die am häufigsten benötigten Konfigurationen hervorgehoben werden. DataAnnotations werden auch von einer Reihe von .NET-Anwendungen wie ASP.NET MVC verstanden, sodass diese Anwendungen dieselben Anmerkungen für clientseitige Überprüfungen nutzen können.

Das -Modell

Gezeigt werden Code-First-DataAnnotations mit einem einfachen Klassenpaar: Blog und Post.

    public class Blog
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string BloggerName { get; set;}
        public virtual ICollection<Post> Posts { get; set; }
    }

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public DateTime DateCreated { get; set; }
        public string Content { get; set; }
        public int BlogId { get; set; }
        public ICollection<Comment> Comments { get; set; }
    }

In der vorliegenden Form folgen die Blog- und Post-Klassen praktischerweise der Code First-Konvention und erfordern keine Optimierungen, um EF-Kompatibilität zu ermöglichen. Sie können die Anmerkungen jedoch auch verwenden, um weitere Informationen zu den Klassen und der Datenbank, der sie zugeordnet sind, für EF bereitzustellen.

 

Schlüssel

Entity Framework setzt voraus, dass jede Entität einen Schlüsselwert hat, der zur Nachverfolgung der Entität verwendet wird. Eine Konvention von Code First sind implizite Schlüsseleigenschaften; Code First sucht nach einer Eigenschaft mit dem Namen „id” oder einer Kombination aus Klassenname und „id”, z. B. „BlogId”. Diese Eigenschaft wird einer Primärschlüsselspalte in der Datenbank zugeordnet.

Die Klassen Blog und Post folgen dieser Konvention. Was wäre, wenn nicht? Was wäre, wenn Blog stattdessen den Namen PrimaryTrackingKey oder sogar foo verwenden würde? Wenn Code First keine Eigenschaft findet, die dieser Konvention entspricht, wird eine Ausnahme ausgelöst, da Entity Framework voraussetzt, dass Sie über eine Schlüsseleigenschaft verfügen. Mit der Schlüsselanmerkung können Sie angeben, welche Eigenschaft als EntityKey verwendet werden soll.

    public class Blog
    {
        [Key]
        public int PrimaryTrackingKey { get; set; }
        public string Title { get; set; }
        public string BloggerName { get; set;}
        public virtual ICollection<Post> Posts { get; set; }
    }

Wenn Sie die Datenbankgenerierungsfunktion von Code First verwenden, verfügt die Blog-Tabelle über eine Primärschlüsselspalte namens PrimaryTrackingKey, die standardmäßig ebenfalls als Identität definiert ist.

Blogtabelle mit Primärschlüssel

Zusammengesetzte Schlüssel

Entity Framework unterstützt zusammengesetzte Schlüssel, d. h. Primärschlüssel, die aus mehreren Eigenschaften bestehen. Beispielsweise könnten Sie eine Passport-Klasse haben, deren Primärschlüssel eine Kombination aus PassportNumber und IssuingCountry ist.

    public class Passport
    {
        [Key]
        public int PassportNumber { get; set; }
        [Key]
        public string IssuingCountry { get; set; }
        public DateTime Issued { get; set; }
        public DateTime Expires { get; set; }
    }

Der Versuch, die oben genannte Klasse in Ihrem EF-Modell zu verwenden, würde zu einer InvalidOperationException führen:

Die Reihenfolge des zusammengesetzten Primärschlüssels für den Typ „Passport“ kann nicht ermittelt werden. Verwenden Sie die ColumnAttribute- oder HasKey-Methode, um eine Reihenfolge für zusammengesetzte Primärschlüssel anzugeben.

Die Verwendung zusammengesetzter Schlüssel durch Entity Framework erfordert, dass Sie eine Reihenfolge für die Schlüsseleigenschaften definieren. Dazu können Sie die Spaltenanmerkung verwenden, um eine Reihenfolge anzugeben.

Hinweis

Der Reihenfolgenwert ist relativ (statt indexbasiert), sodass beliebige Werte verwendet werden können. Beispielsweise wäre 100 und 200 anstelle von 1 und 2 akzeptabel.

    public class Passport
    {
        [Key]
        [Column(Order=1)]
        public int PassportNumber { get; set; }
        [Key]
        [Column(Order = 2)]
        public string IssuingCountry { get; set; }
        public DateTime Issued { get; set; }
        public DateTime Expires { get; set; }
    }

Wenn Sie über Entitäten mit zusammengesetzten Fremdschlüsseln verfügen, müssen Sie dieselbe Spaltenreihenfolge angeben, die Sie für die entsprechenden Primärschlüsseleigenschaften verwendet haben.

Nur die relative Reihenfolge innerhalb der Fremdschlüsseleigenschaften muss identisch sein, die exakten Werte, die Order zugeordnet sind, müssen nicht übereinstimmen. In der folgenden Klasse könnten beispielsweise 3 und 4 anstelle von 1 und 2 verwendet werden.

    public class PassportStamp
    {
        [Key]
        public int StampId { get; set; }
        public DateTime Stamped { get; set; }
        public string StampingCountry { get; set; }

        [ForeignKey("Passport")]
        [Column(Order = 1)]
        public int PassportNumber { get; set; }

        [ForeignKey("Passport")]
        [Column(Order = 2)]
        public string IssuingCountry { get; set; }

        public Passport Passport { get; set; }
    }

Erforderlich

Die Required-Anmerkung teilt EF mit, dass eine bestimmte Eigenschaft erforderlich ist.

Das Hinzufügen von „Required“ zur Title-Eigenschaft erzwingt EF (und MVC), um sicherzustellen, dass die Eigenschaft Daten enthält.

    [Required]
    public string Title { get; set; }

Ohne zusätzliche Code- oder Markupänderungen in der Anwendung führt eine MVC-Anwendung eine clientseitige Validierung durch und erstellt sogar dynamisch eine Nachricht mithilfe der Eigenschafts- und Anmerkungsnamen.

Seite „Erstellen“ mit einem Fehler, der besagt, dass das Titelfeld ein Pflichtfeld ist

Das Attribut „Required“ wirkt sich auch auf die generierte Datenbank aus, indem festgelegt wird, dass die zugeordnete Eigenschaft keine Nullwerte zulassen kann. Beachten Sie, dass sich das Feld „Title“ in „nicht null“ geändert hat.

Hinweis

In einigen Fällen ist es möglicherweise nicht möglich, dass die Spalte in der Datenbank keine Nullwerte zulassen kann, obwohl die Eigenschaft erforderlich ist. Wenn z. B. eine TPH-Vererbungsstrategie verwendet wird, werden Daten für mehrere Typen in einer einzelnen Tabelle gespeichert. Wenn ein abgeleiteter Typ eine erforderliche Eigenschaft enthält, kann nicht festgelegt werden, dass die Spalte keine Nullwerte zulassen kann, da nicht alle Typen in der Hierarchie diese Eigenschaft aufweisen werden.

 

Blogs-Tabelle

 

MaxLength und MinLength

Mit den Attributen MaxLength und MinLength können Sie zusätzliche Eigenschaftenüberprüfungen angeben, genau wie bei Required.

Hier gelten für BloggerName Längenanforderungen. Im Beispiel wird auch veranschaulicht, wie Attribute kombiniert werden.

    [MaxLength(10),MinLength(5)]
    public string BloggerName { get; set; }

Die MaxLength-Anmerkung wirkt sich auf die Datenbank aus, indem die Länge der Eigenschaft auf 10 festgelegt wird.

Blogs-Tabelle mit maximaler Länge in der Spalte „BloggerName“

Die clientseitige MVC-Anmerkung und die serverseitige EF 4.1-Anmerkung berücksichtigen diese Überprüfung, wobei eine Fehlermeldung dynamisch erstellt wird: „Das Feld BloggerName muss eine Zeichenfolge oder ein Arraytyp mit maximaler Länge von 10 sein.” Diese Nachricht ist ein wenig lang. Bei vielen Anmerkungen können Sie eine Fehlermeldung mit dem ErrorMessage-Attribut angeben.

    [MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
    public string BloggerName { get; set; }

Sie können ErrorMessage auch in der Required-Anmerkung angeben.

Seite „Erstellen“ mit benutzerdefinierter Fehlermeldung

 

NotMapped

Die Code-First-Konvention bestimmt, dass jede Eigenschaft, deren Datentyp unterstützt wird, in der Datenbank dargestellt wird. Dies ist jedoch nicht immer in Ihren Anwendungen der Fall. Beispielsweise verfügen Sie möglicherweise über eine Eigenschaft in der Blog-Klasse, die einen Code erstellt, der auf den Feldern „Title“ und „BloggerName“ basiert. Diese Eigenschaft kann dynamisch erstellt werden und muss nicht gespeichert werden. Sie können alle Eigenschaften markieren, die der Datenbank nicht mit der NotMapped-Anmerkung zugeordnet werden, z. B. diese BlogCode-Eigenschaft.

    [NotMapped]
    public string BlogCode
    {
        get
        {
            return Title.Substring(0, 1) + ":" + BloggerName.Substring(0, 1);
        }
    }

 

ComplexType

Es ist nicht ungewöhnlich, Ihre Domänenentitäten in einer Reihe von Klassen zu beschreiben und diese Klassen dann zu überlagern, um eine vollständige Entität zu beschreiben. Beispielsweise können Sie Ihrem Modell eine Klasse namens BlogDetails hinzufügen.

    public class BlogDetails
    {
        public DateTime? DateCreated { get; set; }

        [MaxLength(250)]
        public string Description { get; set; }
    }

Beachten Sie, dass BlogDetails keine Schlüsseleigenschaft aufweist. Im domänengesteuerten Design wird BlogDetails als Wertobjekt bezeichnet. Entity Framework bezieht sich auf Wertobjekte als komplexe Typen.  Komplexe Typen können nicht eigenständig nachverfolgt werden.

Als Eigenschaft in der Blog-Klasse werden BlogDetails jedoch als Teil eines Blog-Objekts nachverfolgt. Damit der Code dies zuerst erkennt, müssen Sie die BlogDetails-Klasse als ComplexTypemarkieren.

    [ComplexType]
    public class BlogDetails
    {
        public DateTime? DateCreated { get; set; }

        [MaxLength(250)]
        public string Description { get; set; }
    }

Jetzt können Sie der Blog-Klasse eine Eigenschaft hinzufügen, um die BlogDetails für diesen Blog darzustellen.

        public BlogDetails BlogDetail { get; set; }

In der Datenbank enthält die Blog-Tabelle alle Eigenschaften des Blogs, einschließlich der Eigenschaften, die in ihrer BlogDetail-Eigenschaft enthalten sind. Standardmäßig ist jedem der Namen des komplexen Typs BlogDetail vorangestellt.

Blogtabelle mit komplexem Typ

ConcurrencyCheck

Mit der ConcurrencyCheck-Anmerkung können Sie eine oder mehrere Eigenschaften kennzeichnen, die für die Parallelitätsprüfung in der Datenbank verwendet werden sollen, wenn Benutzer*innen eine Entität bearbeiten oder löschen. Wenn Sie mit dem EF-Designer gearbeitet haben, entspricht dies der Einstellung des ConcurrencyMode einer Eigenschaft auf Fixed.

Sehen wir uns an, wie ConcurrencyCheck funktioniert, indem dies der BloggerName-Eigenschaft hinzugefügt wird.

    [ConcurrencyCheck, MaxLength(10, ErrorMessage="BloggerName must be 10 characters or less"),MinLength(5)]
    public string BloggerName { get; set; }

Wenn SaveChanges aufgerufen wird, wird aufgrund der ConcurrencyCheck-Anmerkung im BloggerName-Feld der ursprüngliche Wert dieser Eigenschaft in der Aktualisierung verwendet. Der Befehl versucht, die richtige Zeile zu finden, indem nicht nur nach dem Schlüsselwert, sondern auch nach dem ursprünglichen Wert von BloggerName gefiltert wird.  Hier sind die kritischen Teile des an die Datenbank gesendeten UPDATE-Befehls. Wie Sie sehen, wird der Befehl die Zeile aktualisieren, in der PrimaryTrackingKey gleich 1 und ein BloggerName von „Julie“ ist, was der ursprüngliche Wert war, als dieser Blog aus der Datenbank abgerufen wurde.

    where (([PrimaryTrackingKey] = @4) and ([BloggerName] = @5))
    @4=1,@5=N'Julie'

Wenn jemand den Bloggernamen für diesen Blog in der Zwischenzeit geändert hat, tritte bei diesem Update ein Fehler auf, und Ihnen wird eine DbUpdateConcurrencyException gemeldet, die Sie verarbeiten müssen.

 

TimeStamp

Es ist üblicher, Zeilenversions- oder Zeitstempelfelder für die Parallelitätsprüfung zu verwenden. Anstatt jedoch die ConcurrencyCheck-Anmerkung zu verwenden, können Sie die spezifischere TimeStamp-Anmerkung verwenden, solange Bytearray der Typ der Eigenschaft ist. Code First behandelt Timestamp-Eigenschaften genauso wie ConcurrencyCheck-Eigenschaften, stellt aber auch sicher, dass das Datenbankfeld, das Code First generiert, keine Nullwerte zulassen kann. Sie können in einer bestimmten Klasse nur eine Zeitstempeleigenschaft haben.

Fügen Sie der Blog-Klasse die folgende Eigenschaft hinzu:

    [Timestamp]
    public Byte[] TimeStamp { get; set; }

führt dazu, dass Code First in der Datenbanktabelle eine Zeitstempelspalte erstellt, die keine Nullwerte zulassen kann.

Blogs-Tabelle mit Zeitstempelspalte

 

Tabelle und Spalte

Wenn Sie Code First die Datenbank erstellen lassen, können Sie den Namen der Tabellen und Spalten ändern, die erstellt werden. Sie können Code First auch mit einer vorhandenen Datenbank verwenden. Es ist jedoch nicht immer der Fall, dass die Namen der Klassen und Eigenschaften in Ihrer Domäne mit den Namen der Tabellen und Spalten in Ihrer Datenbank übereinstimmen.

Meine Klasse wird mit Blog und nach Konvention benannt, Code First geht zunächst davon aus, dass dies einer Tabelle mit dem Namen Blogs zugeordnet wird. Wenn dies nicht der Fall ist, können Sie den Namen der Tabelle mit dem Attribut Table angeben. Hier gibt die Anmerkung beispielsweise an, dass der Tabellenname InternalBlogsist.

    [Table("InternalBlogs")]
    public class Blog

Die Column-Anmerkung ist ein geschickteres Mittel, um die Attribute einer zugeordneten Spalte anzugeben. Sie können einen Namen, Datentyp oder sogar die Reihenfolge festlegen, in der eine Spalte in der Tabelle angezeigt wird. Hier sehen Sie ein Beispiel des Column-Attributs.

    [Column("BlogDescription", TypeName="ntext")]
    public String Description {get;set;}

Verwechseln Sie das TypeName-Attribut der Spalte nicht mit der DataType DataAnnotation. DataType ist eine Anmerkung, die für die Benutzeroberfläche verwendet und von Code First ignoriert wird.

So sieht die Tabelle nach der Neugenerierung aus. Der Tabellenname wurde in InternalBlogs geändert, und die Description-Spalte aus dem komplexen Typ ist jetzt BlogDescription. Da der Name in der Anmerkung angegeben wurde, verwendet Code First nicht die Konvention, den Spaltennamen mit dem Namen des komplexen Typs zu beginnen.

Blogs-Tabelle und Spalte umbenannt

 

DatabaseGenerated

Ein wichtiges Datenbankfeature ist die Möglichkeit, berechnete Eigenschaften zu haben. Wenn Sie Ihre Code-First-Klassen Tabellen zuordnen, die berechnete Spalten enthalten, möchten Sie nicht, dass Entity Framework versucht, diese Spalten zu aktualisieren. Sie möchten jedoch, dass EF diese Werte aus der Datenbank zurückgibt, nachdem Sie Daten eingefügt oder aktualisiert haben. Sie können die DatabaseGenerated-Anmerkung verwenden, um diese Eigenschaften in Ihrer Klasse zusammen mit der Computed-Enumeration zu kennzeichnen. Andere Enumerationen sind None und Identity.

    [DatabaseGenerated(DatabaseGeneratedOption.Computed)]
    public DateTime DateCreated { get; set; }

Sie können die auf Byte- oder Zeitstempelspalten generierte Datenbank verwenden, wenn Code First die Datenbank generiert. Andernfalls sollten Sie sie nur verwenden, wenn Sie auf bestehende Datenbanken verweisen, da Code First nicht in der Lage sein wird, die Formel für die berechnete Spalte zu bestimmen.

Oben haben Sie gelesen, dass standardmäßig eine Schlüsseleigenschaft, die eine ganze Zahl ist, in der Datenbank zu einem Identitätsschlüssel wird. Dies wäre damit identisch, DatabaseGenerated auf DatabaseGeneratedOption.Identity zu setzen. Wenn dies kein Identitätsschlüssel sein soll, können Sie den Wert auf DatabaseGeneratedOption.None festlegen.

 

Index

Hinweis

Nur ab EF6.1: Das Attribut Index wurde in Entity Framework 6.1 eingeführt. Wenn Sie eine frühere Version verwenden, gelten die Informationen in diesem Abschnitt nicht.

Mit dem IndexAttribute können Sie einen Index für eine oder mehrere Spalten erstellen. Wenn Sie das Attribut einer oder mehreren Eigenschaften hinzufügen, erstellt EF den entsprechenden Index in der Datenbank, wenn es die Datenbank erstellt, oder erstellt ein Gerüst für die entsprechenden CreateIndex-Aufrufe, wenn Sie Code-First-Migrationen verwenden.

Der folgende Code führt beispielsweise dazu, dass in der Rating-Spalte der Posts-Tabelle in der Datenbank ein Index erstellt wird.

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        [Index]
        public int Rating { get; set; }
        public int BlogId { get; set; }
    }

Standardmäßig wird der Index IX_<Eigenschaftsname> benannt („IX_Rating“ im obigen Beispiel). Sie können jedoch auch einen Namen für den Index angeben. Im folgenden Beispiel wird angegeben, dass der Index mit PostRatingIndex benannt werden soll.

    [Index("PostRatingIndex")]
    public int Rating { get; set; }

Indizes sind standardmäßig nicht eindeutig, aber Sie können den mit IsUnique benannten Parameter verwenden, um anzugeben, dass ein Index eindeutig sein soll. Im folgenden Beispiel wird ein eindeutiger Index für einen User-Anmeldenamen eingeführt.

    public class User
    {
        public int UserId { get; set; }

        [Index(IsUnique = true)]
        [StringLength(200)]
        public string Username { get; set; }

        public string DisplayName { get; set; }
    }

Mehrspaltige Indizes

Indizes, die mehrere Spalten umfassen, werden mithilfe desselben Namens in mehreren Index-Anmerkungen für eine bestimmte Tabelle angegeben. Wenn Sie mehrspaltige Indizes erstellen, müssen Sie eine Reihenfolge für die Spalten im Index angeben. Der folgende Code erstellt z. B. einen mehrspaltigen Index für Rating und BlogId namens IX_BlogIdAndRating. BlogId ist die erste Spalte im Index und Rating die zweite.

    public class Post
    {
        public int Id { get; set; }
        public string Title { get; set; }
        public string Content { get; set; }
        [Index("IX_BlogIdAndRating", 2)]
        public int Rating { get; set; }
        [Index("IX_BlogIdAndRating", 1)]
        public int BlogId { get; set; }
    }

 

Beziehungsattribute: InverseProperty und ForeignKey

Hinweis

Diese Seite enthält Informationen zum Einrichten von Beziehungen in Ihrem Code-First-Modell mithilfe von Datenanmerkungen. Allgemeine Informationen zu Beziehungen in EF und zum Zugreifen auf und Bearbeiten von Daten mithilfe von Beziehungen finden Sie unter Beziehungen & Navigationseigenschaften.*

Die Code-First-Konvention behandelt die am häufigsten verwendeten Beziehungen in Ihrem Modell, es gibt jedoch einige Fälle, in denen sie Hilfe benötigt.

Das Ändern des Namens der Schlüsseleigenschaft in der Blog-Klasse hat ein Problem mit der Beziehung zu Post verursacht. 

Beim Generieren der Datenbank sieht Code First die BlogId-Eigenschaft in der Post-Klasse und erkennt sie anhand der Konvention, dass sie einem Klassennamen plus identspricht, als Fremdschlüssel für die Blog-Klasse. In der Blog-Klasse gibt es jedoch keine BlogId-Eigenschaft. Die Lösung ist, eine Navigationseigenschaft in Post zu erstellen und die ForeignKey-DataAnnotation zu verwenden, damit Code First versteht, wie die Beziehung zwischen den beiden Klassen (mithilfe der Post.BlogId-Eigenschaft) erstellt wird, und wie Einschränkungen in der Datenbank angegeben werden.

    public class Post
    {
            public int Id { get; set; }
            public string Title { get; set; }
            public DateTime DateCreated { get; set; }
            public string Content { get; set; }
            public int BlogId { get; set; }
            [ForeignKey("BlogId")]
            public Blog Blog { get; set; }
            public ICollection<Comment> Comments { get; set; }
    }

Die Einschränkung in der Datenbank zeigt eine Beziehung zwischen InternalBlogs.PrimaryTrackingKey und Posts.BlogId

Beziehung zwischen InternalBlogs.PrimaryTrackingKey und Posts.BlogId

InverseProperty wird verwendet, wenn mehrere Beziehungen zwischen Klassen vorliegen.

Im Post-Kurs können Sie nachverfolgen, wer einen Blogbeitrag geschrieben und wer ihn bearbeitet hat. Hier sind zwei neue Navigationseigenschaften für die Post-Klasse.

    public Person CreatedBy { get; set; }
    public Person UpdatedBy { get; set; }

Sie müssen auch in der Person-Klasse eine Hinzufügung vornehmen, die von diesen Eigenschaften referenziert wird. Die Person-Klasse verfügt über Eigenschaften zur Navigation zurück zu Post, eine für alle Beiträge, die von der Person geschrieben wurden, und eine für alle Beiträge, die von dieser Person aktualisiert wurden.

    public class Person
    {
            public int Id { get; set; }
            public string Name { get; set; }
            public List<Post> PostsWritten { get; set; }
            public List<Post> PostsUpdated { get; set; }
    }

Code First kann die Eigenschaften in den beiden Klassen nicht eigenständig abgleichen. Die Datenbanktabelle für Posts sollte über einen Fremdschlüssel für die CreatedBy-Person und einen für die UpdatedBy-Person verfügen, aber der Code erstellt zuerst vier Fremdschlüsseleigenschaften: Person_Id, Person_Id1, CreatedBy_Id und UpdatedBy_Id.

Posts-Tabelle mit zusätzlichen Fremdschlüsseln

Um diese Probleme zu beheben, können Sie mit der InverseProperty-Anmerkung die Ausrichtung der Eigenschaften angeben.

    [InverseProperty("CreatedBy")]
    public List<Post> PostsWritten { get; set; }

    [InverseProperty("UpdatedBy")]
    public List<Post> PostsUpdated { get; set; }

Da die PostsWritten-Eigenschaft in „Person“ weiß, dass sich dies auf den Post-Typ bezieht, wird die Beziehung zu Post.CreatedBy erstellt. Ebenso wird PostsUpdated mit Post.UpdatedByverbunden. Code First wird dann die zusätzlichen Fremdschlüssel nicht erstellen.

Posts-Tabelle ohne zusätzliche Fremdschlüssel

 

Zusammenfassung

Mit DataAnnotations können Sie nicht nur die client- und serverseitige Überprüfung in den ersten Klassen des Codes beschreiben, sondern auch die Annahmen verbessern und sogar korrigieren, die Code First anhand seiner Konventionen zu Ihren Klassen machen wird. Mit DataAnnotations können Sie nicht nur die Generierung von Datenbankschemas steuern, sondern auch die Code First-Klassen einer bereits vorhandenen Datenbank zuordnen.

Sie sind zwar sehr flexibel, denken Sie jedoch daran, dass DataAnnotations nur die am häufigsten benötigten Konfigurationsänderungen bereitstellt, die Sie für Ihre Code First-Klassen vornehmen können. Um Ihre Klassen für einige der Grenzfälle zu konfigurieren, sollten Sie auf den alternativen Konfigurationsmechanismus zurückgreifen, die Fluent-API von Code First.