Erstellen und Konfigurieren eines Modells

EF Core verwendet eine Metadatenmodell, um zu beschreiben, wie die Entitätstypen der Anwendung der zugrunde liegenden Datenbank zugeordnet werden. Dieses Modell wird mit einer Reihe von Konventionen erstellt, also Heuristiken, die nach häufigen Mustern suchen. Dieses Modell kann mithilfe von Zuordnungsattributen (auch als Datenanmerkungen) und/oder Aufrufen der ModelBuilder-Methoden (auch als Fluent-API) in OnModelCreating angepasst werden. Beide setzen die durch Konventionen ausgeführte Konfiguration außer Kraft.

Die meisten Konfigurationen können auf ein Modell angewendet werden, das auf einen beliebigen Datenspeicher ausgerichtet ist. Anbieter können auch eine Konfiguration ermöglichen, die für einen bestimmten Datenspeicher spezifisch ist, und sie können auch die Konfiguration ignorieren, die nicht unterstützt oder nicht zutreffend ist. Eine Dokumentation zu anbieterspezifischen Konfigurationen finden Sie im Abschnitt Datenbankanbieter.

Tipp

Die in diesem Artikel verwendeten Beispiele finden Sie auf GitHub.

Verwenden der Fluent-API zum Konfigurieren eines Modells

Sie können die OnModelCreating-Methode in Ihrem abgeleiteten Kontext außer Kraft setzen und mit der Fluent-API Ihr Modell konfigurieren. Dies ist die wirksamste Konfigurationsmethode und erlaubt die Angabe der Konfiguration, ohne die Entitätsklassen zu verändern. Die Fluent-API-Konfiguration hat die höchste Priorität und überschreibt Konventionen und Datenanmerkungen. Die Konfiguration wird in der Reihenfolge angewendet, in der die Methoden aufgerufen werden, und wenn Konflikte auftreten, setzt der neueste Aufruf die zuvor angegebene Konfiguration außer Kraft.

using Microsoft.EntityFrameworkCore;

namespace EFModeling.EntityProperties.FluentAPI.Required;

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }

    #region Required
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .Property(b => b.Url)
            .IsRequired();
    }
    #endregion
}

public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }
}

Tipp

Informationen zum Anwenden derselben Konfiguration auf mehrere Objekte im Modell finden Sie unter Massenkonfiguration.

Gruppieren der Konfiguration

Um die Größe der OnModelCreating-Methode zu reduzieren, kann die gesamte Konfiguration für einen Entitätstyp in eine separate Klasse extrahiert werden, indem IEntityTypeConfiguration<TEntity> implementiert wird.

public class BlogEntityTypeConfiguration : IEntityTypeConfiguration<Blog>
{
    public void Configure(EntityTypeBuilder<Blog> builder)
    {
        builder
            .Property(b => b.Url)
            .IsRequired();
    }
}

Rufen Sie dann einfach die Configure-Methode aus OnModelCreating auf.

new BlogEntityTypeConfiguration().Configure(modelBuilder.Entity<Blog>());

Anwenden aller Konfigurationen in einer Assembly

Es ist möglich, sämtliche Konfigurationen anzuwenden, die in Typen angegeben werden, indem IEntityTypeConfiguration in einer bestimmten Assembly implementiert wird.

modelBuilder.ApplyConfigurationsFromAssembly(typeof(BlogEntityTypeConfiguration).Assembly);

Hinweis

Die Reihenfolge, in der die Konfigurationen angewendet werden, ist nicht definiert. Diese Methode sollte daher nur verwendet werden, wenn die Reihenfolge keine Rolle spielt.

Verwenden von EntityTypeConfigurationAttribute für Entitätstypen

Anstatt explizit Configure aufzurufen, kann stattdessen EntityTypeConfigurationAttribute für den Entitätstyp festgelegt werden, sodass EF Core die entsprechende Konfiguration finden und verwenden kann. Beispiele:

[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Isbn { get; set; }
}

Dieses Attribut bedeutet, dass EF Core die angegebene IEntityTypeConfiguration-Implementierung verwendet, wenn der Entitätstyp Book in einem Modell enthalten ist. Der Entitätstyp wird dem Modell mit einem der gängigen Verfahren hinzugefügt, beispielsweise durch das Erstellen einer DbSet<TEntity>-Eigenschaft für den Entitätstyp:

public class BooksContext : DbContext
{
    public DbSet<Book> Books { get; set; }

    //...

Alternativ kann er bei OnModelCreating registriert werden:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Book>();
}

Hinweis

EntityTypeConfigurationAttribute-Typen werden in einer Assembly nicht automatisch erkannt. Entitätstypen müssen dem Modell hinzugefügt werden, bevor das Attribut für diesen Entitätstyp erkannt wird.

Verwenden von Datenanmerkungen zum Konfigurieren eines Modells

Sie können auch bestimmte Attribute (sogenannte Datenanmerkungen) auf Ihre Klassen und Eigenschaften anwenden. Datenanmerkungen setzen Konventionen außer Kraft, werden aber ihrerseits von der Fluent-API-Konfiguration außer Kraft gesetzt.

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using Microsoft.EntityFrameworkCore;

namespace EFModeling.EntityProperties.DataAnnotations.Annotations;

internal class MyContext : DbContext
{
    public DbSet<Blog> Blogs { get; set; }
}

[Table("Blogs")]
public class Blog
{
    public int BlogId { get; set; }

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

Integrierte Konventionen

EF Core enthält viele Konventionen zum Erstellen von Modellen, die standardmäßig aktiviert sind. Sie finden alle in der Liste der Klassen, die die Schnittstelle IConvention implementieren. Diese Liste enthält jedoch keine Konventionen, die von Datenbankanbietern von Drittparteien und Plug-Ins eingeführt wurden.

Anwendungen können diese Konventionen entfernen oder ersetzen und neue benutzerdefinierte Konventionen hinzufügen, die Konfigurationen für Muster anwenden, die von EF nicht sofort erkannt werden.

Tipp

Der unten gezeigte Code stammt aus ModelBuildingConventionsSample.cs.

Entfernen einer vorhandenen Konvention

Manchmal ist eine der integrierten Konventionen für Ihre Anwendung möglicherweise nicht geeignet, in diesem Fall kann sie entfernt werden.

Tipp

Wenn Ihr Modell keine Zuordnungsattribute (auch als Datenanmerkungen bezeichnet) für die Konfiguration verwendet, können alle Konventionen mit dem Namen, der auf AttributeConvention endet, sicher entfernt werden, um die Modellerstellung zu beschleunigen.

Beispiel: Erstellen Sie keine Indizes für Fremdschlüsselspalten.

Normalerweise ist es sinnvoll, Indizes für FK-Spalten (Fremdschlüsselspalten) zu erstellen. Daher gibt es hierfür eine integrierte Konvention: ForeignKeyIndexConvention. Wenn wir das Modell debug view (Debugansicht) für einen Post-Entitätstyp mit Beziehungen zu Blog und Author betrachten, erkennen wir, dass zwei Indizes erstellt werden: einer für den Fremdschlüssel BlogId und der andere für den Fremdschlüssel AuthorId.

  EntityType: Post
    Properties:
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
      AuthorId (no field, int?) Shadow FK Index
      BlogId (no field, int) Shadow Required FK Index
    Navigations:
      Author (Author) ToPrincipal Author Inverse: Posts
      Blog (Blog) ToPrincipal Blog Inverse: Posts
    Keys:
      Id PK
    Foreign keys:
      Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
      Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade
    Indexes:
      AuthorId
      BlogId

Der Mehraufwand für Indizes ist jedoch höher, und es ist möglicherweise nicht immer geeignet, sie für alle FK-Spalten zu erstellen. Hierzu kann die ForeignKeyIndexConvention-Klasse beim Erstellen des Modells entfernt werden:

protected override void ConfigureConventions(ModelConfigurationBuilder configurationBuilder)
{
    configurationBuilder.Conventions.Remove(typeof(ForeignKeyIndexConvention));
}

In der Debugansicht des Modells für Post sehen Sie jetzt, dass die Indizes für die FKs nicht erstellt wurden:

  EntityType: Post
    Properties:
      Id (int) Required PK AfterSave:Throw ValueGenerated.OnAdd
      AuthorId (no field, int?) Shadow FK
      BlogId (no field, int) Shadow Required FK
    Navigations:
      Author (Author) ToPrincipal Author Inverse: Posts
      Blog (Blog) ToPrincipal Blog Inverse: Posts
    Keys:
      Id PK
    Foreign keys:
      Post {'AuthorId'} -> Author {'Id'} ToDependent: Posts ToPrincipal: Author ClientSetNull
      Post {'BlogId'} -> Blog {'Id'} ToDependent: Posts ToPrincipal: Blog Cascade

Bei Bedarf können Indizes weiterhin explizit für Fremdschlüsselspalten erstellt werden, entweder mithilfe der IndexAttribute oder mit Konfiguration in OnModelCreating.

Debugansicht

Auf die Model Builder-Debugansicht kann im Debugger Ihrer IDE zugegriffen werden. Beispielsweise mit Visual Studio:

Accessing the model builder debug view from the Visual Studio debugger

Es kann auch direkt über den Code auf sie zugegriffen werden, um beispielsweise die Debugansicht an die Konsole zu senden:

Console.WriteLine(context.Model.ToDebugString());

Die Debugansicht verfügt über ein kurzes Formular und ein langes Formular. Das lange Formular enthält auch alle Anmerkungen, die nützlich sein können, wenn Sie relationale oder anbieterspezifische Metadaten anzeigen müssen. Auf die lange Ansicht kann auch über den Code zugegriffen werden:

Console.WriteLine(context.Model.ToDebugString(MetadataDebugStringOptions.LongDefault));