BeziehungenRelationships

Eine Beziehung definiert, wie zwei Entitäten miteinander in Beziehung stehen.A relationship defines how two entities relate to each other. In einer relationalen Datenbank wird dies durch eine FOREIGN KEY-Einschränkung repräsentiert.In a relational database, this is represented by a foreign key constraint.

Hinweis

Die meisten Beispiele in diesem Artikel verwenden eine 1: n-Beziehung, um die Konzepte zu veranschaulichen.Most of the samples in this article use a one-to-many relationship to demonstrate concepts. Beispiele für 1:1-und m:n-Beziehungen finden Sie im Abschnitt andere Beziehungsmuster am Ende des Artikels.For examples of one-to-one and many-to-many relationships see the Other Relationship Patterns section at the end of the article.

Definition von BegriffenDefinition of terms

Es gibt eine Reihe von Begriffen, die zum Beschreiben von Beziehungen verwendet werden.There are a number of terms used to describe relationships

  • Abhängige Entität: Dies ist die Entität, die die Fremdschlüssel Eigenschaften enthält.Dependent entity: This is the entity that contains the foreign key properties. Wird manchmal auch als ' Child ' der Beziehung bezeichnet.Sometimes referred to as the 'child' of the relationship.

  • Prinzipal Entität: Dies ist die Entität, die die Eigenschaften des primären/Alternativen Schlüssels enthält.Principal entity: This is the entity that contains the primary/alternate key properties. Wird manchmal auch als "übergeordnetes Element" der Beziehung bezeichnet.Sometimes referred to as the 'parent' of the relationship.

  • Prinzipal Schlüssel: Die Eigenschaften, die die Prinzipal Entität eindeutig identifizieren.Principal key: The properties that uniquely identify the principal entity. Hierbei kann es sich um den Primärschlüssel oder einen alternativen Schlüssel handeln.This may be the primary key or an alternate key.

  • Fremdschlüssel: Die Eigenschaften in der abhängigen Entität, die zum Speichern der Prinzipal Schlüsselwerte für die verknüpfte Entität verwendet werden.Foreign key: The properties in the dependent entity that are used to store the principal key values for the related entity.

  • Navigations Eigenschaft: Eine für die Prinzipal-und/oder abhängige Entität definierte Eigenschaft, die auf die verknüpfte Entität verweist.Navigation property: A property defined on the principal and/or dependent entity that references the related entity.

    • Auflistungs Navigations Eigenschaft: Eine Navigations Eigenschaft, die Verweise auf viele Verwandte Entitäten enthält.Collection navigation property: A navigation property that contains references to many related entities.

    • Verweis Navigations Eigenschaft: Eine Navigations Eigenschaft, die einen Verweis auf eine einzelne verknüpfte Entität enthält.Reference navigation property: A navigation property that holds a reference to a single related entity.

    • Umgekehrte Navigations Eigenschaft: Bei der Erörterung einer bestimmten Navigations Eigenschaft bezieht sich dieser Begriff auf die Navigations Eigenschaft am anderen Ende der Beziehung.Inverse navigation property: When discussing a particular navigation property, this term refers to the navigation property on the other end of the relationship.

  • Selbst verweisende Beziehung: Eine Beziehung, in der die abhängigen und die Prinzipal Entitäts Typen identisch sind.Self-referencing relationship: A relationship in which the dependent and the principal entity types are the same.

Der folgende Code zeigt eine 1: n-Beziehung zwischen Blog und. PostThe following code shows a one-to-many relationship between Blog and Post

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

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}
  • Post ist die abhängige EntitätPost is the dependent entity

  • Blog ist die Prinzipal EntitätBlog is the principal entity

  • Blog.BlogId ist der Prinzipal Schlüssel (in diesem Fall handelt es sich um einen Primärschlüssel anstelle eines alternativen Schlüssels)Blog.BlogId is the principal key (in this case it is a primary key rather than an alternate key)

  • Post.BlogId ist der FremdschlüsselPost.BlogId is the foreign key

  • Post.Blog ist eine Verweis Navigations Eigenschaft.Post.Blog is a reference navigation property

  • Blog.Posts ist eine Auflistungs Navigations Eigenschaft.Blog.Posts is a collection navigation property

  • Post.Blog ist die umgekehrte Navigations Eigenschaft von Blog.Posts (und umgekehrt).Post.Blog is the inverse navigation property of Blog.Posts (and vice versa)

KonventionenConventions

Standardmäßig wird eine Beziehung erstellt, wenn eine Navigations Eigenschaft für einen Typ erkannt wird.By default, a relationship will be created when there is a navigation property discovered on a type. Eine Eigenschaft wird als Navigations Eigenschaft betrachtet, wenn der Typ, auf den Sie verweist, nicht vom aktuellen Datenbankanbieter als Skalartyp zugeordnet werden kann.A property is considered a navigation property if the type it points to can not be mapped as a scalar type by the current database provider.

Hinweis

Die von der Konvention ermittelten Beziehungen richten sich immer nach dem Primärschlüssel der Prinzipal Entität.Relationships that are discovered by convention will always target the primary key of the principal entity. Um einen alternativen Schlüssel als Ziel zu verwenden, muss mithilfe der flüssigen API eine zusätzliche Konfiguration durchgeführt werden.To target an alternate key, additional configuration must be performed using the Fluent API.

Vollständig definierte BeziehungenFully defined relationships

Das gängigste Muster für Beziehungen besteht darin, dass für beide Enden der Beziehung Navigations Eigenschaften und eine Fremdschlüssel Eigenschaft definiert sind, die in der abhängigen Entitäts Klasse definiert ist.The most common pattern for relationships is to have navigation properties defined on both ends of the relationship and a foreign key property defined in the dependent entity class.

  • Wenn zwischen zwei Typen ein paar Navigations Eigenschaften gefunden wird, werden diese als umgekehrte Navigations Eigenschaften derselben Beziehung konfiguriert.If a pair of navigation properties is found between two types, then they will be configured as inverse navigation properties of the same relationship.

  • Wenn die abhängige Entität eine Eigenschaft mit einem Namen enthält, der mit einem dieser Muster übereinstimmt, wird Sie als Fremdschlüssel konfiguriert:If the dependent entity contains a property with a name matching one of these patterns then it will be configured as the foreign key:

    • <navigation property name><principal key property name>
    • <navigation property name>Id
    • <principal entity name><principal key property name>
    • <principal entity name>Id
public class Blog
{
    public int BlogId { get; set; }
    public string Url { get; set; }

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

In diesem Beispiel werden die markierten Eigenschaften zum Konfigurieren der Beziehung verwendet.In this example the highlighted properties will be used to configure the relationship.

Hinweis

Wenn die Eigenschaft der Primärschlüssel oder ein Typ ist, der nicht mit dem Prinzipal Schlüssel kompatibel ist, wird Sie nicht als Fremdschlüssel konfiguriert.If the property is the primary key or is of a type not compatible with the principal key then it won't be configured as the foreign key.

Hinweis

Vor EF Core 3,0 wurde die Eigenschaft mit dem gleichen Namen wie die Prinzipal Schlüsseleigenschaft ebenfalls als Fremdschlüssel abgeglichen .Before EF Core 3.0 the property named exactly the same as the principal key property was also matched as the foreign key

Keine Fremdschlüssel EigenschaftNo foreign key property

Es wird empfohlen, eine Fremdschlüssel Eigenschaft in der abhängigen Entitäts Klasse zu definieren, die jedoch nicht erforderlich ist.While it is recommended to have a foreign key property defined in the dependent entity class, it is not required. Wenn keine Fremdschlüssel Eigenschaft gefunden wird, wird eine Schatten-Fremdschlüssel Eigenschaft mit dem Namen <navigation property name><principal key property name> oder, <principal entity name><principal key property name> Wenn keine Navigation für den abhängigen Typ vorhanden ist, eingefügt.If no foreign key property is found, a shadow foreign key property will be introduced with the name <navigation property name><principal key property name> or <principal entity name><principal key property name> if no navigation is present on the dependent type.

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

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

In diesem Beispiel ist der Schatten Fremdschlüssel, weil der vorangestellt wird, BlogId dass der Navigations Name redundant ist.In this example the shadow foreign key is BlogId because prepending the navigation name would be redundant.

Hinweis

Wenn bereits eine Eigenschaft mit demselben Namen vorhanden ist, wird dem Namen der Schatten Eigenschaft eine Zahl angehängt.If a property with the same name already exists then the shadow property name will be suffixed with a number.

Einzelne Navigations EigenschaftSingle navigation property

Das Einschließen von nur einer Navigations Eigenschaft (keine umgekehrte Navigation und keine Fremdschlüssel Eigenschaft) reicht aus, um eine Beziehung gemäß der Konvention zu definieren.Including just one navigation property (no inverse navigation, and no foreign key property) is enough to have a relationship defined by convention. Sie können auch eine einzelne Navigations Eigenschaft und eine Fremdschlüssel Eigenschaft haben.You can also have a single navigation property and a foreign key property.

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

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
}

EinschränkungenLimitations

Wenn mehrere Navigations Eigenschaften zwischen zwei Typen definiert sind (d. h. mehr als nur ein Navigations Paar, das aufeinander zeigen), sind die Beziehungen, die von den Navigations Eigenschaften dargestellt werden, mehrdeutig.When there are multiple navigation properties defined between two types (that is, more than just one pair of navigations that point to each other) the relationships represented by the navigation properties are ambiguous. Sie müssen Sie manuell konfigurieren, um die Mehrdeutigkeit aufzulösen.You will need to manually configure them to resolve the ambiguity.

Kaskadierendes DeleteCascade delete

Gemäß der Konvention wird CASCADE DELETE für erforderliche Beziehungen und clientsetnull für optionale Beziehungen auf Cascade festgelegt.By convention, cascade delete will be set to Cascade for required relationships and ClientSetNull for optional relationships. Cascade bedeutet, dass abhängige Entitäten ebenfalls gelöscht werden.Cascade means dependent entities are also deleted. Clientsetnull bedeutet, dass abhängige Entitäten, die nicht in den Arbeitsspeicher geladen werden, unverändert bleiben und manuell gelöscht oder aktualisiert werden müssen, um auf eine gültige Prinzipal Entität zu verweisen.ClientSetNull means that dependent entities that are not loaded into memory will remain unchanged and must be manually deleted, or updated to point to a valid principal entity. Bei Entitäten, die in den Arbeitsspeicher geladen werden, wird EF Core versucht, die Fremdschlüssel Eigenschaften auf NULL festzulegen.For entities that are loaded into memory, EF Core will attempt to set the foreign key properties to null.

Den Unterschied zwischen erforderlichen und optionalen Beziehungen finden Sie im Abschnitt erforderliche und optionale Beziehungen .See the Required and Optional Relationships section for the difference between required and optional relationships.

Weitere Informationen zu den verschiedenen Lösch Verhalten und den von der Konvention verwendeten Standardwerten finden Sie unter Cascade Delete .See Cascade Delete for more details about the different delete behaviors and the defaults used by convention.

Manuelle KonfigurationManual configuration

Um eine Beziehung in der fließenden API zu konfigurieren, müssen Sie zunächst die Navigations Eigenschaften ermitteln, die die Beziehung bilden.To configure a relationship in the Fluent API, you start by identifying the navigation properties that make up the relationship. HasOne oder HasMany identifiziert die Navigations Eigenschaft für den Entitätstyp, für den Sie mit der Konfiguration beginnen.HasOne or HasMany identifies the navigation property on the entity type you are beginning the configuration on. Anschließend verketten Sie einen Aufrufen von WithOne oder WithMany , um die umgekehrte Navigation zu ermitteln.You then chain a call to WithOne or WithMany to identify the inverse navigation. HasOne/WithOnewerden für Verweis Navigations Eigenschaften verwendet und für Auflistungs HasMany / WithMany Navigations Eigenschaften verwendet.HasOne/WithOne are used for reference navigation properties and HasMany/WithMany are used for collection navigation properties.

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts);
    }
}

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

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

Einzelne Navigations EigenschaftSingle navigation property

Wenn Sie nur über eine Navigations Eigenschaft verfügen, gibt es Parameter lose über Ladungen von WithOne und WithMany .If you only have one navigation property then there are parameterless overloads of WithOne and WithMany. Dies gibt an, dass ein Verweis oder eine Auflistung am anderen Ende der Beziehung konzeptionell ist, aber in der Entitäts Klasse ist keine Navigations Eigenschaft enthalten.This indicates that there is conceptually a reference or collection on the other end of the relationship, but there is no navigation property included in the entity class.

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasMany(b => b.Posts)
            .WithOne();
    }
}

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

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
}

Konfigurieren von Navigations EigenschaftenConfiguring navigation properties

Hinweis

Diese Funktion wurde in EF Core 5,0 eingeführt.This feature was introduced in EF Core 5.0.

Nachdem die Navigations Eigenschaft erstellt wurde, müssen Sie Sie möglicherweise weiter konfigurieren.After the navigation property has been created, you may need to further configure it.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(b => b.Posts)
        .WithOne();

    modelBuilder.Entity<Blog>()
        .Navigation(b => b.Posts)
            .UsePropertyAccessMode(PropertyAccessMode.Property);
}

Hinweis

Dieser Befehl kann nicht zum Erstellen einer Navigations Eigenschaft verwendet werden.This call cannot be used to create a navigation property. Sie wird nur verwendet, um eine Navigations Eigenschaft zu konfigurieren, die zuvor durch Definieren einer Beziehung oder einer Konvention erstellt wurde.It is only used to configure a navigation property which has been previously created by defining a relationship or from a convention.

FremdschlüsselForeign key

Sie können die fließende API verwenden, um zu konfigurieren, welche Eigenschaft als Fremdschlüssel Eigenschaft für eine bestimmte Beziehung verwendet werden soll:You can use the Fluent API to configure which property should be used as the foreign key property for a given relationship:

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .HasForeignKey(p => p.BlogForeignKey);
    }
}

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

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogForeignKey { get; set; }
    public Blog Blog { get; set; }
}

Schatten-FremdschlüsselShadow foreign key

Sie können die Zeichen folgen Überladung von verwenden HasForeignKey(...) , um eine Schatten Eigenschaft als Fremdschlüssel zu konfigurieren (Weitere Informationen finden Sie unter Schatten Eigenschaften ).You can use the string overload of HasForeignKey(...) to configure a shadow property as a foreign key (see Shadow Properties for more information). Es wird empfohlen, die Schatten Eigenschaft explizit dem Modell hinzuzufügen, bevor Sie als Fremdschlüssel verwendet wird (wie unten gezeigt).We recommend explicitly adding the shadow property to the model before using it as a foreign key (as shown below).

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Add the shadow property to the model
        modelBuilder.Entity<Post>()
            .Property<int>("BlogForeignKey");

        // Use the shadow property as a foreign key
        modelBuilder.Entity<Post>()
            .HasOne(p => p.Blog)
            .WithMany(b => b.Posts)
            .HasForeignKey("BlogForeignKey");
    }
}

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

    public List<Post> Posts { get; set; }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public Blog Blog { get; set; }
}

Name der FOREIGN KEY-EinschränkungForeign key constraint name

Gemäß der Konvention werden Foreign Key-Einschränkungen beim Ziel einer relationalen Datenbank als "FK" benannt _ <dependent type name> _ <principal type name> _ <foreign key property name> .By convention, when targeting a relational database, foreign key constraints are named FK_<dependent type name>_<principal type name>_<foreign key property name>. Bei zusammengesetzten Fremdschlüsseln <foreign key property name> wird zu einer durch Trennzeichen getrennten Liste von Fremdschlüssel Eigenschaftsnamen.For composite foreign keys, <foreign key property name> becomes an underscore separated list of foreign key property names.

Sie können den Einschränkungs Namen auch wie folgt konfigurieren:You can also configure the constraint name as follows:

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasOne(p => p.Blog)
        .WithMany(b => b.Posts)
        .HasForeignKey(p => p.BlogId)
        .HasConstraintName("ForeignKey_Post_Blog");
}

Ohne Navigations EigenschaftWithout navigation property

Sie müssen nicht unbedingt eine Navigations Eigenschaft bereitstellen.You don't necessarily need to provide a navigation property. Sie können auf einer Seite der Beziehung einfach einen Fremdschlüssel bereitstellen.You can simply provide a foreign key on one side of the relationship.

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasOne<Blog>()
            .WithMany()
            .HasForeignKey(p => p.BlogId);
    }
}

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

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public int BlogId { get; set; }
}

Prinzipal SchlüsselPrincipal key

Wenn Sie möchten, dass der Fremdschlüssel auf eine andere Eigenschaft als den Primärschlüssel verweist, können Sie mit der fließend-API die Prinzipal Schlüsseleigenschaft für die Beziehung konfigurieren.If you want the foreign key to reference a property other than the primary key, you can use the Fluent API to configure the principal key property for the relationship. Die Eigenschaft, die Sie als Prinzipal Schlüssel konfigurieren, wird automatisch als alternativer Schlüsseleingerichtet.The property that you configure as the principal key will automatically be setup as an alternate key.

class MyContext : DbContext
{
    public DbSet<Car> Cars { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<RecordOfSale>()
            .HasOne(s => s.Car)
            .WithMany(c => c.SaleHistory)
            .HasForeignKey(s => s.CarLicensePlate)
            .HasPrincipalKey(c => c.LicensePlate);
    }
}

public class Car
{
    public int CarId { get; set; }
    public string LicensePlate { get; set; }
    public string Make { get; set; }
    public string Model { get; set; }

    public List<RecordOfSale> SaleHistory { get; set; }
}

public class RecordOfSale
{
    public int RecordOfSaleId { get; set; }
    public DateTime DateSold { get; set; }
    public decimal Price { get; set; }

    public string CarLicensePlate { get; set; }
    public Car Car { get; set; }
}

Erforderliche und optionale BeziehungenRequired and optional relationships

Mit der fließend-API können Sie konfigurieren, ob die Beziehung erforderlich oder optional ist.You can use the Fluent API to configure whether the relationship is required or optional. Letztendlich steuert dies, ob die Fremdschlüssel Eigenschaft erforderlich oder optional ist.Ultimately this controls whether the foreign key property is required or optional. Dies ist besonders nützlich, wenn Sie einen Schatten Zustands-Fremdschlüssel verwenden.This is most useful when you are using a shadow state foreign key. Wenn Sie über eine Fremdschlüssel Eigenschaft in der Entitäts Klasse verfügen, wird die Eignung der Beziehung abhängig davon bestimmt, ob die Fremdschlüssel Eigenschaft erforderlich oder optional ist (Weitere Informationen finden Sie unter erforderliche und optionale Eigenschaften ).If you have a foreign key property in your entity class then the requiredness of the relationship is determined based on whether the foreign key property is required or optional (see Required and Optional properties for more information).

Die Fremdschlüssel Eigenschaften befinden sich auf dem abhängigen Entitätstyp. Wenn Sie daher als erforderlich konfiguriert werden, bedeutet dies, dass für jede abhängige Entität eine entsprechende Prinzipal Entität erforderlich ist.The foreign key properties are located on the dependent entity type, so if they are configured as required it means that every dependent entity is required to have a corresponding principal entity.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasOne(p => p.Blog)
        .WithMany(b => b.Posts)
        .IsRequired();
}

Hinweis

Durch IsRequired(false) das Aufrufen von wird auch die Fremdschlüssel Eigenschaft optional, sofern Sie nicht anderweitig konfiguriert ist.Calling IsRequired(false) also makes the foreign key property optional unless it's configured otherwise.

Kaskadierendes DeleteCascade delete

Sie können die fließende API verwenden, um das kaskadierte Lösch Verhalten für eine bestimmte Beziehung explizit zu konfigurieren.You can use the Fluent API to configure the cascade delete behavior for a given relationship explicitly.

Eine ausführliche Erläuterung der einzelnen Optionen finden Sie unter Cascade Delete .See Cascade Delete for a detailed discussion of each option.

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Post>()
        .HasOne(p => p.Blog)
        .WithMany(b => b.Posts)
        .OnDelete(DeleteBehavior.Cascade);
}

Andere BeziehungsmusterOther relationship patterns

1:1One-to-one

Eine zu 1 Beziehung hat eine Verweis Navigations Eigenschaft auf beiden Seiten.One to one relationships have a reference navigation property on both sides. Sie folgen denselben Konventionen wie 1: n-Beziehungen, aber es wird ein eindeutiger Index für die Fremdschlüssel Eigenschaft eingeführt, um sicherzustellen, dass nur ein abhängiger mit den einzelnen Prinzipalen verknüpft ist.They follow the same conventions as one-to-many relationships, but a unique index is introduced on the foreign key property to ensure only one dependent is related to each principal.

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

    public BlogImage BlogImage { get; set; }
}

public class BlogImage
{
    public int BlogImageId { get; set; }
    public byte[] Image { get; set; }
    public string Caption { get; set; }

    public int BlogId { get; set; }
    public Blog Blog { get; set; }
}

Hinweis

EF wählt eine der Entitäten aus, die abhängig von der Fähigkeit, eine Fremdschlüssel Eigenschaft zu erkennen, abhängig ist.EF will choose one of the entities to be the dependent based on its ability to detect a foreign key property. Wenn die falsche Entität als abhängig ausgewählt wird, können Sie diese mithilfe der flüssigen API korrigieren.If the wrong entity is chosen as the dependent, you can use the Fluent API to correct this.

Beim Konfigurieren der Beziehung mit der flüssigen API verwenden Sie die HasOne -Methode und die- WithOne Methode.When configuring the relationship with the Fluent API, you use the HasOne and WithOne methods.

Wenn Sie den Fremdschlüssel konfigurieren, müssen Sie den abhängigen Entitätstyp angeben. Beachten Sie den generischen Parameter, der HasForeignKey in der nachfolgenden Auflistung bereitgestellt wird.When configuring the foreign key you need to specify the dependent entity type - notice the generic parameter provided to HasForeignKey in the listing below. In einer 1: n-Beziehung ist klar, dass die Entität mit der Verweis Navigation die abhängige ist und die mit der Auflistung der Prinzipal ist.In a one-to-many relationship it is clear that the entity with the reference navigation is the dependent and the one with the collection is the principal. Dies ist jedoch in einer eins-zu-eins-Beziehung nicht der Fall, daher muss Sie explizit definiert werden.But this is not so in a one-to-one relationship - hence the need to explicitly define it.

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Blog>()
            .HasOne(b => b.BlogImage)
            .WithOne(i => i.Blog)
            .HasForeignKey<BlogImage>(b => b.BlogForeignKey);
    }
}

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

    public BlogImage BlogImage { get; set; }
}

public class BlogImage
{
    public int BlogImageId { get; set; }
    public byte[] Image { get; set; }
    public string Caption { get; set; }

    public int BlogForeignKey { get; set; }
    public Blog Blog { get; set; }
}

Die abhängige Seite wird standardmäßig als optional betrachtet, kann jedoch als erforderlich konfiguriert werden.The dependent side is considered optional by default, but can be configured as required. EF überprüft jedoch nicht, ob eine abhängige Entität bereitgestellt wurde, sodass diese Konfiguration nur einen Unterschied macht, wenn die Daten Bank Zuordnung die Durchsetzung zulässt.However EF will not validate whether a dependent entity was provided, so this configuration will only make a difference when the database mapping allows it to be enforced. Ein häufiges Szenario hierfür sind Referenztypen, die standardmäßig Tabellen Aufteilung verwenden.A common scenario for this are reference owned types that use table splitting by default.

modelBuilder.Entity<Order>(ob =>
{
    ob.OwnsOne(
        o => o.ShippingAddress,
        sa =>
        {
            sa.Property(p => p.Street).IsRequired();
            sa.Property(p => p.City).IsRequired();
        });

    ob.Navigation(o => o.ShippingAddress)
        .IsRequired();
});

Mit dieser Konfiguration werden die Spalten, die entsprechen, ShippingAddress in der Datenbank als nicht auf NULL festlegbar gekennzeichnet.With this configuration the columns corresponding to ShippingAddress will be marked as non-nullable in the database.

Hinweis

Wenn Sie Verweis Typen verwenden, die keine NULL-Werte zulassen, ist das Aufrufen von IsRequired nicht erforderlich.If you are using non-nullable reference types calling IsRequired is not necessary.

Hinweis

Die Möglichkeit, zu konfigurieren, ob die abhängige erforderlich ist, wurde in EF Core 5,0 eingeführt.The ability to configure whether the dependent is required was introduced in EF Core 5.0.

M:nMany-to-many

Für m:n-Beziehungen ist auf beiden Seiten eine Auflistungs Navigations Eigenschaft erforderlich.Many to many relationships require a collection navigation property on both sides. Sie werden gemäß der Konvention wie andere Beziehungstypen erkannt.They will be discovered by convention like other types of relationships.

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public ICollection<Tag> Tags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

    public ICollection<Post> Posts { get; set; }
}

Die Art und Weise, in der diese Beziehung in der Datenbank implementiert wird, ist eine jointabelle, die Fremdschlüssel für Post und enthält Tag .The way this relationship is implemented in the database is by a join table that contains foreign keys to both Post and Tag. Dies ist beispielsweise der Fall, den EF in einer relationalen Datenbank für das obige Modell erstellt.For example this is what EF will create in a relational database for the above model.

CREATE TABLE [Posts] (
    [PostId] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([PostId])
);

CREATE TABLE [Tags] (
    [TagId] nvarchar(450) NOT NULL,
    CONSTRAINT [PK_Tags] PRIMARY KEY ([TagId])
);

CREATE TABLE [PostTag] (
    [PostsId] int NOT NULL,
    [TagsId] nvarchar(450) NOT NULL,
    CONSTRAINT [PK_PostTag] PRIMARY KEY ([PostsId], [TagsId]),
    CONSTRAINT [FK_PostTag_Posts_PostsId] FOREIGN KEY ([PostsId]) REFERENCES [Posts] ([PostId]) ON DELETE CASCADE,
    CONSTRAINT [FK_PostTag_Tags_TagsId] FOREIGN KEY ([TagsId]) REFERENCES [Tags] ([TagId]) ON DELETE CASCADE
);

Intern erstellt EF einen Entitätstyp, der die jointabelle darstellt, die als joinentitätstyp bezeichnet wird.Internally, EF creates an entity type to represent the join table that will be referred to as the join entity type. Hierfür gibt es keinen spezifischen CLR-Typ, der verwendet werden kann Dictionary<string, object> .There is no specific CLR type that can be used for this, so Dictionary<string, object> is used. Mehrere m:n-Beziehungen können im Modell vorhanden sein. Daher muss dem joinentitätstyp ein eindeutiger Name zugewiesen werden, in diesem Fall PostTag .More than one many-to-many relationships can exist in the model, therefore the join entity type must be given a unique name, in this case PostTag. Die Funktion, die dies zulässt, wird als Entitätstyp mit gemeinsamer Typbezeichnung bezeichnet.The feature that allows this is called shared-type entity type.

Die m:n-Navigationen werden als "Skip Navigationen" bezeichnet, da Sie den joinentitätstyp effektiv überspringen.The many to many navigations are called skip navigations as they effectively skip over the join entity type. Wenn Sie die Massen Konfiguration verwenden, können alle Skip-Navigationen aus abgerufen werden GetSkipNavigations .If you are employing bulk configuration all skip navigations can be obtained from GetSkipNavigations.

foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
    foreach (var skipNavigation in entityType.GetSkipNavigations())
    {
        Console.WriteLine(entityType.DisplayName() + "." + skipNavigation.Name);
    }
}

Es kommt häufig vor, dass die Konfiguration auf den Join-Entitätstyp angewendet wird.It is common to apply configuration to the join entity type. Diese Aktion kann mithilfe von durchgeführt werden UsingEntity .This action can be accomplished via UsingEntity.

modelBuilder
    .Entity<Post>()
    .HasMany(p => p.Tags)
    .WithMany(p => p.Posts)
    .UsingEntity(j => j.ToTable("PostTags"));

Modell Ausgangsdaten können mithilfe anonymer Typen für den Join-Entitätstyp bereitgestellt werden.Model seed data can be provided for the join entity type by using anonymous types. Sie können die modelldebugansicht überprüfen, um die von der Konvention erstellten Eigenschaftsnamen zu ermitteln.You can examine the model debug view to determine the property names created by convention.

modelBuilder
    .Entity<Post>()
    .HasData(new Post { PostId = 1, Title = "First"});

modelBuilder
    .Entity<Tag>()
    .HasData(new Tag { TagId = "ef" });

modelBuilder
    .Entity<Post>()
    .HasMany(p => p.Tags)
    .WithMany(p => p.Posts)
    .UsingEntity(j => j.HasData(new { PostsPostId = 1, TagsTagId = "ef" }));

Zusätzliche Daten können im Join-Entitätstyp gespeichert werden, aber hierfür ist es am besten, einen beständigen CLR-Typ zu erstellen.Additional data can be stored in the join entity type, but for this it's best to create a bespoke CLR type. Beim Konfigurieren der Beziehung mit einem benutzerdefinierten Join-Entitätstyp müssen beide Fremdschlüssel explizit angegeben werden.When configuring the relationship with a custom join entity type both foreign keys need to be specified explicitly.

class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options)
        : base(options)
    {
    }

    public DbSet<Post> Posts { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Post>()
            .HasMany(p => p.Tags)
            .WithMany(p => p.Posts)
            .UsingEntity<PostTag>(
                j => j
                    .HasOne(pt => pt.Tag)
                    .WithMany(t => t.PostTags)
                    .HasForeignKey(pt => pt.TagId),
                j => j
                    .HasOne(pt => pt.Post)
                    .WithMany(p => p.PostTags)
                    .HasForeignKey(pt => pt.PostId),
                j =>
                {
                    j.Property(pt => pt.PublicationDate).HasDefaultValueSql("CURRENT_TIMESTAMP");
                    j.HasKey(t => new { t.PostId, t.TagId });
                });
    }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public ICollection<Tag> Tags { get; set; }
    public List<PostTag> PostTags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

    public ICollection<Post> Posts { get; set; }
    public List<PostTag> PostTags { get; set; }
}

public class PostTag
{
    public DateTime PublicationDate { get; set; }

    public int PostId { get; set; }
    public Post Post { get; set; }

    public string TagId { get; set; }
    public Tag Tag { get; set; }
}

Hinweis

Die Möglichkeit zum Konfigurieren von m:n-Beziehungen wurde in EF Core 5,0 eingeführt. verwenden Sie für die vorherige Version die folgende Vorgehensweise.The ability to configure many-to-many relationships was introduced in EF Core 5.0, for previous version use the following approach.

Sie können auch eine m:n-Beziehung darstellen, indem Sie einfach den Join-Entitätstyp hinzufügen und zwei separate 1: n-Beziehungen Mapping.You can also represent a many-to-many relationship by just adding the join entity type and mapping two separate one-to-many relationships.

public class MyContext : DbContext
{
    public MyContext(DbContextOptions<MyContext> options)
        : base(options)
    {
    }

    public DbSet<Post> Posts { get; set; }
    public DbSet<Tag> Tags { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<PostTag>()
            .HasKey(t => new { t.PostId, t.TagId });

        modelBuilder.Entity<PostTag>()
            .HasOne(pt => pt.Post)
            .WithMany(p => p.PostTags)
            .HasForeignKey(pt => pt.PostId);

        modelBuilder.Entity<PostTag>()
            .HasOne(pt => pt.Tag)
            .WithMany(t => t.PostTags)
            .HasForeignKey(pt => pt.TagId);
    }
}

public class Post
{
    public int PostId { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

    public List<PostTag> PostTags { get; set; }
}

public class Tag
{
    public string TagId { get; set; }

    public List<PostTag> PostTags { get; set; }
}

public class PostTag
{
    public DateTime PublicationDate { get; set; }

    public int PostId { get; set; }
    public Post Post { get; set; }

    public string TagId { get; set; }
    public Tag Tag { get; set; }
}

Hinweis

Der Gerüstbau für m:n-Beziehungen anhand der Datenbank wird noch nicht unterstützt.Support for scaffolding many-to-many relationships from the database is not yet added. Siehe Nachverfolgung von Issue.See tracking issue.

Zusätzliche RessourcenAdditional resources