Attributs de mappage (ou annotations de données) pour les relations

Les attributs de mappage sont utilisés pour modifier ou remplacer la configuration découverte par des conventions de génération de modèles. La configuration réalisée par les attributs de mappage peut elle-même être remplacée par l’API de génération de modèles utilisée dans OnModelCreating.

Important

Ce document traite uniquement des attributs de mappage dans le contexte de la configuration des relations. D’autres utilisations des attributs de mappage sont abordées plus largement dans les sections correspondantes de la documentation de modélisation.

Conseil

Le code ci-dessous est disponible dans MappingAttributes.cs.

Où trouver des attributs de mappage

De nombreux attributs de mappage proviennent des espaces de noms System.ComponentModel.DataAnnotations et System.ComponentModel.DataAnnotations.Schema. Les attributs de ces espaces de noms font partie de l’infrastructure de base dans toutes les versions prises en charge de .NET, et ne nécessitent donc pas l’installation de packages NuGet supplémentaires. Ces attributs de mappage, couramment appelés « annotations de données », sont utilisés par de nombreuses infrastructures telles que EF Core, EF6, ASP.NET Core MVC, et d’autres encore. Ils sont aussi utilisés pour la validation.

L’utilisation d’annotations de données dans de nombreuses technologies, aussi bien pour le mappage que pour la validation, a entraîné des différences de sémantique entre les technologies. Tous les nouveaux attributs de mappage conçus pour EF Core sont désormais spécifiques à EF Core, conservant ainsi leur sémantique pour une utilisation simple et claire. Ces attributs sont contenus dans le package NuGet Microsoft.EntityFrameworkCore.Abstractions. Celui-ci est inclus en tant que dépendance chaque fois que le package principal Microsoft.EntityFrameworkCore ou que l’un des packages de fournisseur de base de données associés, est utilisé. Toutefois, le package Abstractions est léger et peut être référencé directement par le code d’application sans apporter toutes les dépendances de EF Core.

RequiredAttribute

RequiredAttribute est appliqué à une propriété pour indiquer qu’elle ne peut pas être null. Dans le contexte des relations, [Required] est généralement utilisé pour une propriété de clé étrangère. Ainsi, la clé étrangère ne peut accepter la valeur Nul et la relation est obligatoirement requise. Par exemple, avec les types suivants, la propriété Post.BlogId devient non-nullable et la relation devient obligatoire.

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

Remarque

Lorsque vous utilisez des types de référence nulle C#, la propriété BlogId est dans ce cas déjà non-nullable, ce qui signifie que l’attribut [Required] n’aura aucun impact.

[Required] a le même effet lorsqu’il est placé dans la navigation dépendante. Autrement dit, il rend la clé étrangère non-nullable et la relation est requise. Par exemple :

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

Si [Required] se trouve dans la navigation dépendante et que la propriété de clé étrangère est en cache, la propriété cachée est rendue non-nullable et la relation est alors requise. Par exemple :

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

Remarque

L’utilisation de [Required] du côté de la navigation principale d’une relation n’a aucun effet.

ForeignKeyAttribute

ForeignKeyAttribute sert à connecter une propriété de clé étrangère à ses navigations. [ForeignKey] peut être positionné sur la propriété de clé étrangère avec le nom de la navigation dépendante. Par exemple :

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] peut être placé sur la navigation dépendante ou principale avec le nom de la propriété à utiliser comme clé étrangère. Par exemple :

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

Lorsque [ForeignKey] est placé sur une navigation et que le nom fourni ne correspond à aucun nom de propriété, une propriété cachée portant ce nom sera créée pour agir comme clé étrangère. Par exemple :

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 est utilisé pour connecter une navigation avec son inverse. Par exemple, dans les types d’entités suivants, deux relations existent entre Blog et Post. Sans configuration, les conventions EF ne peuvent pas déterminer quelles navigations entre les deux types doivent être jumelées. L’ajout de [InverseProperty] à l’une des navigations jumelées résout cette ambiguïté et permet à EF de générer le modèle.

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

Important

[InverseProperty] est nécessaire uniquement lorsque plusieurs relations existent entre les mêmes types. Dans le cas d’une relation unique, les deux navigations sont jumelées automatiquement.

DeleteBehaviorAttribute

Par convention, EF utilise ClientSetNullDeleteBehavior pour les relations facultatives et le comportement Cascade pour les relations requises. Cela peut être modifié en plaçant DeleteBehaviorAttribute sur l’une des navigations de la relation. Par exemple :

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

Pour plus d’informations sur les comportements en cascade, consultez la documentation Suppression en cascade.