Atributos de mapeamento (também conhecidos como anotações de dados) para relações

Atributos de mapeamento são usados para modificar ou substituir a configuração descoberta por convenções de criação de modelo. A configuração executada por atributos de mapeamento pode ser substituída pela API de criação de modelo usada em OnModelCreating.

Importante

Esse documento abrange apenas atributos de mapeamento no contexto da configuração de relação. Outros usos de atributos de mapeamento são abordados nas seções relevantes da documentação de modelagem mais ampla.

Dica

O código abaixo pode ser encontrado em MappingAttributes.cs.

Onde obter atributos de mapeamento

Muitos atributos de mapeamento têm origem nos namespaces System.ComponentModel.DataAnnotations e System.ComponentModel.DataAnnotations.Schema. Os atributos nesses namespaces são incluídos como parte da estrutura base em todas as versões com suporte do .NET e, portanto, não exigem a instalação de nenhum pacote NuGet adicional. Esses atributos de mapeamento geralmente são chamados de "anotações de dados" e são usados por uma variedade de estruturas, incluindo EF Core, EF6, ASP.NET Core MVC e assim por diante. Eles também são usados para validação.

O uso de anotações de dados em várias tecnologias e para mapeamento e validação levou a diferenças na semântica entre tecnologias. Todos os novos atributos de mapeamento projetados para o EF Core agora são específicos do EF Core, mantendo assim a semântica e o uso simples e claro. Esses atributos estão contidos no pacote NuGet Microsoft.EntityFrameworkCore.Abstractions. Esse pacote é incluído como uma dependência sempre que o pacote principal Microsoft.EntityFrameworkCore ou um dos pacotes do provedor de banco de dados associados é usado. No entanto, o pacote Abstractions é um pacote leve que pode ser referenciado diretamente pelo código do aplicativo sem trazer todo o EF Core e suas dependências.

RequiredAttribute

RequiredAttribute é aplicado a uma propriedade para indicar que a propriedade não pode ser null. No contexto de relações, [Required] geralmente é usado em uma propriedade de chave estrangeira. Fazer isso torna a chave estrangeira não anulável, tornando a relação necessária. Por exemplo, com os seguintes tipos, a propriedade Post.BlogId se torna não anulável e a relação se torna necessária.

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

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

    public Blog Blog { get; init; }
}

Observação

Ao usar tipos de referência anuláveis em C#, a propriedade BlogId nesse exemplo já é não anulável, o que significa que o atributo [Required] não terá nenhum efeito.

[Required] colocado na navegação dependente tem o mesmo efeito. Ou seja, tornando a chave estrangeira não anulável e, assim, tornando a relação necessária. Por exemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    public string BlogId { get; set; }

    [Required]
    public Blog Blog { get; init; }
}

Se [Required] for encontrado na navegação dependente e a propriedade de chave estrangeira estiver em estado de sombra, a propriedade de sombra será tornada não anulável, tornando a relação necessária. Por exemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    [Required]
    public Blog Blog { get; init; }
}

Observação

O uso de [Required] no lado da navegação principal de uma relação não tem efeito.

ForeignKeyAttribute

ForeignKeyAttribute é usado para conectar uma propriedade de chave estrangeira com suas navegações. [ForeignKey] pode ser colocado na propriedade de chave estrangeira com o nome da navegação dependente. Por exemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    [ForeignKey(nameof(Blog))]
    public string BlogKey { get; set; }

    public Blog Blog { get; init; }
}

Ou [ForeignKey] pode ser colocado na navegação dependente ou principal com o nome da propriedade a ser usada como chave estrangeira. Por exemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    public string BlogKey { get; set; }

    [ForeignKey(nameof(BlogKey))]
    public Blog Blog { get; init; }
}

Quando [ForeignKey] é colocado em uma navegação e o nome fornecido não corresponde a nenhum nome de propriedade, uma propriedade de sombra com esse nome será criada para atuar como a chave estrangeira. Por exemplo:

public class Blog
{
    public string Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }

    [ForeignKey("BlogKey")]
    public Blog Blog { get; init; }
}

InversePropertyAttribute

InversePropertyAttribute é usado para conectar uma navegação com seu inverso. Por exemplo, nos seguintes tipos de entidade, há duas relações entre Blog e Post. Sem qualquer configuração, as convenções de EF não podem determinar quais navegações entre os dois tipos devem ser emparelhadas. Adicionar [InverseProperty] a uma das navegações emparelhadas resolve essa ambiguidade e permite que o EF crie o modelo.

public class Blog
{
    public int Id { get; set; }

    [InverseProperty("Blog")]
    public List<Post> Posts { get; } = new();

    public int FeaturedPostId { get; set; }
    public Post FeaturedPost { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; }

    public Blog Blog { get; init; }
}

Importante

[InverseProperty] só é necessário quando há mais de uma relação entre os mesmos tipos. Com uma única relação, as duas navegações são emparelhadas automaticamente.

DeleteBehaviorAttribute

Por convenção, o EF usa as ClientSetNullDeleteBehavior como relações ideais e o comportamento Cascade como relações necessárias. Isso pode ser alterado colocando o DeleteBehaviorAttribute em uma das navegações da relação. Por exemplo:

public class Blog
{
    public int Id { get; set; }
    public List<Post> Posts { get; } = new();
}

public class Post
{
    public int Id { get; set; }
    public int BlogId { get; set; }

    [DeleteBehavior(DeleteBehavior.Restrict)]
    public Blog Blog { get; init; }
}

Consulte Exclusão em cascata para obter mais informações sobre comportamentos em cascata.