RelaçõesRelationships

Uma relação define como duas entidades se relacionam entre si.A relationship defines how two entities relate to each other. Em um banco de dados relacional, isso é representado por uma restrição foreign key.In a relational database, this is represented by a foreign key constraint.

Observação

A maioria dos exemplos neste artigo usa uma relação um-para-muitos para demonstrar conceitos.Most of the samples in this article use a one-to-many relationship to demonstrate concepts. Para obter exemplos de relações um para um e muitos-para-muitos, consulte o outros padrões de relação seção no final do artigo.For examples of one-to-one and many-to-many relationships see the Other Relationship Patterns section at the end of the article.

Definição de termosDefinition of Terms

Há um número de termos usados para descrever relaçõesThere are a number of terms used to describe relationships

  • Entidade dependente: essa é a entidade que contém a propriedade de chave estrangeira (s).Dependent entity: This is the entity that contains the foreign key property(s). Às vezes chamado de "filho" da relação.Sometimes referred to as the 'child' of the relationship.

  • Entidade principal: essa é a entidade que contém as propriedades de chave alternativo/primário.Principal entity: This is the entity that contains the primary/alternate key property(s). Às vezes chamado de 'parent' da relação.Sometimes referred to as the 'parent' of the relationship.

  • Chave estrangeira: a propriedade (s) em que é usada para armazenar os valores da propriedade de chave principal que a entidade está relacionada à entidade dependente.Foreign key: The property(s) in the dependent entity that is used to store the values of the principal key property that the entity is related to.

  • Chave da entidade: a propriedade (s) que identifica exclusivamente a entidade principal.Principal key: The property(s) that uniquely identifies the principal entity. Isso pode ser a chave primária ou uma chave alternativa.This may be the primary key or an alternate key.

  • Propriedade de navegação: uma propriedade definida na entidade dependente e/ou entidade de segurança que contém uma referência (s) para a entidade relacionada (s).Navigation property: A property defined on the principal and/or dependent entity that contains a reference(s) to the related entity(s).

    • Propriedade de navegação de coleção: uma propriedade de navegação que contém referências a várias entidades relacionadas.Collection navigation property: A navigation property that contains references to many related entities.

    • Referência de propriedade de navegação: uma propriedade de navegação que contém uma referência a uma única entidade relacionada.Reference navigation property: A navigation property that holds a reference to a single related entity.

    • Propriedade de navegação inverso: ao discutir uma propriedade de navegação em particular, este termo refere-se para a propriedade de navegação na outra extremidade da relação.Inverse navigation property: When discussing a particular navigation property, this term refers to the navigation property on the other end of the relationship.

A listagem de código a seguir mostra uma relação um-para-muitos entre Blog e PostThe following code listing shows a one-to-many relationship between Blog and Post

  • Post é a entidade dependentePost is the dependent entity

  • Blog é a entidade principalBlog is the principal entity

  • Post.BlogId é a chave estrangeiraPost.BlogId is the foreign key

  • Blog.BlogId é a chave de entidade (nesse caso é uma chave primária em vez de uma chave alternativa)Blog.BlogId is the principal key (in this case it is a primary key rather than an alternate key)

  • Post.Blog é uma propriedade de navegação de referênciaPost.Blog is a reference navigation property

  • Blog.Posts é uma propriedade de navegação de coleçãoBlog.Posts is a collection navigation property

  • Post.Blog é a propriedade de navegação inverso do Blog.Posts (e vice-versa)Post.Blog is the inverse navigation property of Blog.Posts (and vice versa)

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

ConvençõesConventions

Por convenção, uma relação será criada quando há uma propriedade de navegação descoberta em um tipo.By convention, a relationship will be created when there is a navigation property discovered on a type. Uma propriedade é considerada uma propriedade de navegação, se o tipo que ele aponta não pode ser mapeado como um tipo escalar pelo provedor de banco de dados atual.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.

Observação

As relações que são descobertas pela convenção sempre serão direcionada para a chave primária da entidade principal.Relationships that are discovered by convention will always target the primary key of the principal entity. Para direcionar para uma chave alternativa, uma configuração adicional deve ser executada usando a API do Fluent.To target an alternate key, additional configuration must be performed using the Fluent API.

Relações totalmente definidasFully Defined Relationships

O padrão mais comum para relações é ter as propriedades de navegação definidas em ambas as extremidades da relação e uma propriedade de chave estrangeira definida na classe de entidade dependente.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.

  • Se um par de propriedades de navegação é encontrado entre dois tipos, eles serão configurados como propriedades de navegação inversa da mesma relação.If a pair of navigation properties is found between two types, then they will be configured as inverse navigation properties of the same relationship.

  • Se a entidade dependente contém uma propriedade chamada <primary key property name>, <navigation property name><primary key property name>, ou <principal entity name><primary key property name> e em seguida, ele será configurado como a chave estrangeira.If the dependent entity contains a property named <primary key property name>, <navigation property name><primary key property name>, or <principal entity name><primary key property name> then it will be configured as the foreign key.

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

Aviso

Se houver várias propriedades de navegação, definidas entre dois tipos (ou seja, mais de um par distinto de navegações que apontam para si), em seguida, nenhuma relação será criada por convenção, e você precisará configurá-las para identificar manualmente como o par de propriedades de navegação para cima.If there are multiple navigation properties defined between two types (that is, more than one distinct pair of navigations that point to each other), then no relationships will be created by convention and you will need to manually configure them to identify how the navigation properties pair up.

Nenhuma propriedade de chave estrangeiraNo Foreign Key Property

Embora seja recomendável ter uma propriedade de chave estrangeira definida na classe de entidade dependente, não é necessário.While it is recommended to have a foreign key property defined in the dependent entity class, it is not required. Se nenhuma propriedade de chave estrangeira for encontrada, uma propriedade de chave estrangeira de sombra será introduzida com o nome <navigation property name><principal key property name> (consulte propriedades de sombra para obter mais informações).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> (see Shadow Properties for more information).

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

Propriedade de navegação únicoSingle Navigation Property

Incluindo apenas uma propriedade de navegação (nenhuma navegação inversa e nenhuma propriedade de chave estrangeira) é suficiente para ter uma relação definida por convenção.Including just one navigation property (no inverse navigation, and no foreign key property) is enough to have a relationship defined by convention. Você também pode ter uma propriedade de navegação e uma propriedade de chave estrangeira.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; }
}

Excluir em cascataCascade Delete

Por convenção, a exclusão em cascata será definida como Cascade para as relações necessárias e ClientSetNull para relações opcionais.By convention, cascade delete will be set to Cascade for required relationships and ClientSetNull for optional relationships. CASCADE significa entidades dependentes também serão excluídas.Cascade means dependent entities are also deleted. ClientSetNull significa que as entidades dependentes que não são carregadas na memória permanecerá inalterado e deve ser excluídas manualmente ou atualizada para apontar para uma entidade principal válida.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. Para entidades que são carregadas na memória, o EF Core tentará definir as propriedades de chave estrangeiras como nulo.For entities that are loaded into memory, EF Core will attempt to set the foreign key properties to null.

Consulte a relações obrigatórios e opcionais seção para a diferença entre as relações obrigatórios e opcionais.See the Required and Optional Relationships section for the difference between required and optional relationships.

Ver exclusão em cascata para obter mais detalhes sobre os diferentes comportamentos e os padrões usados pela convenção de exclusão.See Cascade Delete for more details about the different delete behaviors and the defaults used by convention.

Anotações de dadosData Annotations

Há duas anotações de dados que podem ser usadas para configurar as relações, [ForeignKey] e [InverseProperty].There are two data annotations that can be used to configure relationships, [ForeignKey] and [InverseProperty].

[ForeignKey][ForeignKey]

Você pode usar as anotações de dados para configurar qual propriedade deve ser usada como a propriedade de chave estrangeira para uma determinada relação.You can use the Data Annotations to configure which property should be used as the foreign key property for a given relationship. Normalmente, isso é feito quando a propriedade de chave estrangeira não for descoberta por convenção.This is typically done when the foreign key property is not discovered by convention.

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

    [ForeignKey("BlogForeignKey")]
    public Blog Blog { get; set; }
}

Dica

O [ForeignKey] anotação pode ser colocada em uma das propriedades de navegação na relação.The [ForeignKey] annotation can be placed on either navigation property in the relationship. Ele não precisa ir na propriedade de navegação na classe de entidade dependente.It does not need to go on the navigation property in the dependent entity class.

[InverseProperty][InverseProperty]

Você pode usar as anotações de dados para configurar como as propriedades de navegação em entidades dependentes e principais ao emparelhar.You can use the Data Annotations to configure how navigation properties on the dependent and principal entities pair up. Normalmente, isso é feito quando há mais de um par de propriedades de navegação entre dois tipos de entidade.This is typically done when there is more than one pair of navigation properties between two entity types.

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

    public int AuthorUserId { get; set; }
    public User Author { get; set; }

    public int ContributorUserId { get; set; }
    public User Contributor { get; set; }
}

public class User
{
    public string UserId { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }

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

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

API fluenteFluent API

Para configurar uma relação na API do Fluent, inicie identificando as propriedades de navegação que compõem a relação.To configure a relationship in the Fluent API, you start by identifying the navigation properties that make up the relationship. HasOne ou HasMany identifica a propriedade de navegação no tipo de entidade que você estiver iniciando a configuração em.HasOne or HasMany identifies the navigation property on the entity type you are beginning the configuration on. Uma chamada para então encadear WithOne ou WithMany para identificar a navegação inversa.You then chain a call to WithOne or WithMany to identify the inverse navigation. HasOne/WithOne são usados para as propriedades de navegação de referência e HasMany / WithMany são usados para as propriedades de navegação de coleção.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; }
}

Propriedade de navegação únicoSingle Navigation Property

Se você tiver apenas uma propriedade de navegação, há sobrecargas sem parâmetro de WithOne e WithMany.If you only have one navigation property then there are parameterless overloads of WithOne and WithMany. Isso indica que há conceitualmente uma referência ou uma coleção na outra extremidade da relação, mas não há nenhuma propriedade de navegação incluída na classe de entidade.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; }
}

Chave estrangeiraForeign Key

Você pode usar a API Fluent para configurar qual propriedade deve ser usada como a propriedade de chave estrangeira para uma determinada relação.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; }
}

A listagem de código a seguir mostra como configurar uma chave estrangeira composta.The following code listing shows how to configure a composite foreign key.

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

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<Car>()
            .HasKey(c => new { c.State, c.LicensePlate });

        modelBuilder.Entity<RecordOfSale>()
            .HasOne(s => s.Car)
            .WithMany(c => c.SaleHistory)
            .HasForeignKey(s => new { s.CarState, s.CarLicensePlate });
    }
}

public class Car
{
    public string State { 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 CarState { get; set; }
    public string CarLicensePlate { get; set; }
    public Car Car { get; set; }
}

Você pode usar a sobrecarga de cadeia de caracteres de HasForeignKey(...) para configurar uma propriedade de sombra como uma chave estrangeira (consulte propriedades de sombra para obter mais informações).You can use the string overload of HasForeignKey(...) to configure a shadow property as a foreign key (see Shadow Properties for more information). É recomendável adicionar explicitamente a propriedade de sombra para o modelo antes de usá-lo como uma chave estrangeira (conforme mostrado abaixo).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; }
}

Chave da entidadePrincipal Key

Se você quiser que a chave estrangeira para fazer referência a uma propriedade que não seja a chave primária, você pode usar a API Fluent para configurar a propriedade de chave de entidade de segurança para a relação.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. A propriedade que você configurar como a chave será a entidade de segurança automaticamente ser configurado como uma chave alternativa (consulte chaves alternativas para obter mais informações).The property that you configure as the principal key will automatically be setup as an alternate key (see Alternate Keys for more information).

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

A listagem de código a seguir mostra como configurar uma chave de entidade composta.The following code listing shows how to configure a composite principal 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 => new { s.CarState, s.CarLicensePlate })
            .HasPrincipalKey(c => new { c.State, c.LicensePlate });
    }
}

public class Car
{
    public int CarId { get; set; }
    public string State { 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 CarState { get; set; }
    public string CarLicensePlate { get; set; }
    public Car Car { get; set; }
}

Aviso

A ordem em que você especificar propriedades de chave de entidade de segurança deve corresponder à ordem na qual eles são especificados para a chave estrangeira.The order in which you specify principal key properties must match the order in which they are specified for the foreign key.

Relações obrigatórios e opcionaisRequired and Optional Relationships

Você pode usar a API Fluent para configurar se a relação é obrigatório ou opcional.You can use the Fluent API to configure whether the relationship is required or optional. Por fim, isso controla se a propriedade de chave estrangeira é obrigatório ou opcional.Ultimately this controls whether the foreign key property is required or optional. Isso é mais útil quando você estiver usando uma chave estrangeira do estado de sombra.This is most useful when you are using a shadow state foreign key. Se você tiver uma propriedade de chave estrangeira em sua classe de entidade, o requiredness da relação é determinado com base em se a propriedade de chave estrangeira é obrigatória ou opcional (consulte propriedades obrigatórias e opcionais para obter mais informações informações).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).

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

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

Excluir em cascataCascade Delete

Você pode usar a API Fluent para configurar o comportamento de exclusão em cascata para uma determinada relação explicitamente.You can use the Fluent API to configure the cascade delete behavior for a given relationship explicitly.

Ver exclusão em cascata na seção salvando dados para uma discussão detalhada de cada opção.See Cascade Delete on the Saving Data section for a detailed discussion of each option.

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)
            .OnDelete(DeleteBehavior.Cascade);
    }
}

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

Outros padrões de relaçãoOther Relationship Patterns

Um para umOne-to-one

Relações um-para-um têm uma propriedade de navegação de referência em ambos os lados.One to one relationships have a reference navigation property on both sides. Eles seguem as mesmas convenções de relações um-para-muitos, mas um índice exclusivo é introduzido na propriedade de chave estrangeira para garantir que apenas um dependente está relacionado a cada entidade de segurança.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; }
}

Observação

O EF escolherá uma das entidades para ser dependente com base em sua capacidade de detectar uma propriedade de chave estrangeira.EF will choose one of the entities to be the dependent based on its ability to detect a foreign key property. Se a entidade errada é escolhida como o dependente, você pode usar a API Fluent para corrigir isso.If the wrong entity is chosen as the dependent, you can use the Fluent API to correct this.

Ao configurar a relação com a API Fluent, que você usar o HasOne e WithOne métodos.When configuring the relationship with the Fluent API, you use the HasOne and WithOne methods.

Ao configurar a chave estrangeira, você precisa especificar o tipo de entidade dependente - Observe o parâmetro genérico fornecido para HasForeignKey na lista abaixo.When configuring the foreign key you need to specify the dependent entity type - notice the generic parameter provided to HasForeignKey in the listing below. Em uma relação um-para-muitos, é claro que a entidade com a navegação de referência é dependente e o com a coleção é a entidade de segurança.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. Mas isso não é então uma relação individual -, portanto, a necessidade de defini-lo explicitamente.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(p => p.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; }
}

Muitos-para-muitosMany-to-many

Ainda não há suporte para relações muitos-para-muitos sem uma classe de entidade para representar a tabela de junção.Many-to-many relationships without an entity class to represent the join table are not yet supported. No entanto, você pode representar uma relação muitos-para-muitos com a inclusão de uma classe de entidade para a tabela de junção e duas relações de um-para-muitos separado mapeamento.However, you can represent a many-to-many relationship by including an entity class for the join table and mapping two separate one-to-many relationships.

class MyContext : DbContext
{
    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 int PostId { get; set; }
    public Post Post { get; set; }

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