Partilhar via


Mapeando atributos (também conhecidos como anotações de dados) para relacionamentos

Os atributos de mapeamento são usados para modificar ou substituir a configuração descoberta pelas convenções de construção de modelos. A configuração executada pelos atributos de mapeamento pode ser substituída pela API de construção de modelo usada no OnModelCreating.

Importante

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

Sugestão

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

Onde obter atributos de mapeamento

Muitos atributos de mapeamento vêm dos 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 suportadas do .NET e, portanto, não exigem a instalação de nenhum pacote NuGet adicional. Esses atributos de mapeamento são comumente 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 muitas 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 sua semântica e uso simples e claro. Esses atributos estão contidos no pacote NuGet Microsoft.EntityFrameworkCore.Abstractions . Este pacote é incluído como uma dependência sempre que o pacote principal Microsoft.EntityFrameworkCore , ou um dos pacotes de 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.

Atributo Obrigatório

RequiredAttribute é aplicado a uma propriedade para indicar que a propriedade não pode ser null. No contexto de relacionamentos, [Required] geralmente é usado numa propriedade de chave estrangeira. Isso torna a chave estrangeira não anulável, tornando assim a relação necessária. Por exemplo, com os seguintes tipos, a Post.BlogId propriedade torna-se não anulável e a relação torna-se 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 BlogId propriedade neste exemplo já não é nula, o que significa que o [Required] atributo não terá efeito.

[Required] colocado na navegação dependente tem o mesmo efeito. Ou seja, tornar a chave estrangeira não anulável e, assim, tornar 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, então a propriedade em estado de sombra se torna não anulável, tornando assim 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

Usar [Required] no lado de navegação principal de um relacionamento 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 associada ao 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 na principal, com o nome da propriedade a utilizar 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; }
}

Atributo de Propriedade Inversa

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 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 construa 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ária quando existe mais do que uma relação entre os mesmos tipos. Com uma única relação, as duas navegações são sincronizadas automaticamente.

DeleteBehaviorAttribute

Por convenção, o EF usa, para relacionamentos opcionais, o ClientSetNullDeleteBehavior e, para relacionamentos necessários, o comportamento Cascade. 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.