Introduction aux relations

Ce document fournit une introduction simple décrivant les relations dans les modèles objet et les bases de données relationnelles, et montrant notamment comment EF Core mappe entre les deux.

Les relations dans les modèles objet

Une relation définit les liens entre deux entités. Par exemple, lorsque vous modélisez des billets dans un blog, chaque billet est lié au blog sur lequel il est publié, et le blog est lui-même lié à tous ces billets.

Dans un langage orienté objet tel que C#, le blog et le billet sont généralement représentés par deux catégories : Blog et Post. Par exemple :

public class Blog
{
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }
}
public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PublishedOn { get; set; }
    public bool Archived { get; set; }
}

Dans les catégories ci-dessus, rien n’indique que Blog et Post sont liés. Cela peut être ajouté au modèle objet en insérant la référence dePost dans la catégorie Blog sur lequel il est publié :

public class Post
{
    public string Title { get; set; }
    public string Content { get; set; }
    public DateOnly PublishedOn { get; set; }
    public bool Archived { get; set; }

    public Blog Blog { get; set; }
}

De même, la direction opposée de la même relation peut être représentée sous la forme d’une collection d’objets Postsur chaque Blog :

public class Blog
{
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }

    public ICollection<Post> Posts { get; }
}

Dans EF Core , cette connexion de Blog vers Post, et inversement de Post vers Blog est appelée « relation ».

Important

Une relation unique peut généralement fonctionner dans les deux sens. Dans cet exemple, la connexion est établie à partir de Blog vers Post via la propriétéBlog.Posts, et dans le sens inverse de Post à Blog, via la propriétéPost.Blog. Il s’agit d’une relationunique, il n’y en n’a pas deux.

Conseil

Dans EF Core, les propriétés Blog.Posts et Post.Blog sont appelées « navigations ».

Les relations dans les bases de données relationnelles

Les bases de données relationnelles sont des relations utilisant des clés étrangères. Par exemple, avec SQL Server ou Azure SQL, les tables suivantes peuvent être utilisées pour représenter nos catégories Post et Blog :

CREATE TABLE [Posts] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) NULL,
    [PublishedOn] datetime2 NOT NULL,
    [Archived] bit NOT NULL,
    [BlogId] int NOT NULL,
    CONSTRAINT [PK_Posts] PRIMARY KEY ([Id]),
    CONSTRAINT [FK_Posts_Blogs_BlogId] FOREIGN KEY ([BlogId]) REFERENCES [Blogs] ([Id]) ON DELETE CASCADE);

CREATE TABLE [Blogs] (
    [Id] int NOT NULL IDENTITY,
    [Name] nvarchar(max) NULL,
    [SiteUri] nvarchar(max) NULL,
    CONSTRAINT [PK_Blogs] PRIMARY KEY ([Id]));

Dans ce modèle relationnel, les tables Posts et Blogs sont chacune dotées d’une colonne « clé primaire ». La valeur de la clé primaire identifie chaque billet ou chaque blog de manière unique. En outre, la table Posts comporte une colonne « clé étrangère ». La colonne clé primaire BlogsId est référencée par la colonne de clé étrangère BlogId de la table Posts. Cette colonne est « contrainte » de sorte que toute valeur dans la colonne BlogIdde Postsdoit correspondre à une valeur dans la colonne Id de Blogs. Cette correspondance détermine à quel blog chaque billet est lié. Par exemple, si la valeur BlogId dans une ligne de la table Posts est 7, le billet représenté par cette ligne sera publié dans le blog avec la clé primaire 7.

Mappage des relations dans EF Core

Le mappage de relation dans EF Core consiste à mapper la représentation de clé primaire/clé étrangère utilisée dans une base de données relationnelle aux références entre les objets utilisés dans un modèle objet.

D’un point de vue rudimentaire, cela implique :

  • L’ajout d’une propriété de clé primaire à chaque type d’entité.
  • L’ajout d’une propriété de clé étrangère à un type d’entité.
  • L’association des références entre les types d’entités avec les clés primaires et étrangères pour créer une configuration de relation unique.

Une fois ce mappage effectué, EF modifie si nécessaire les valeurs de clé étrangère lorsque les références entre les objets changent. De la même façon, il modifie si nécessaire les références entre les objets lorsque les valeurs de clé étrangère changent.

Remarque

Les clés primaires sont aussi utilisées pour d’autres fonctionnalités que les relations de mappage. Pour plus d’informations, consultez la rubrique Clés.

Par exemple, les types d’entités montrés ci-dessus peuvent être mis à jour avec des propriétés de clé primaire et étrangère :

public class Blog
{
    public int Id { get; set; }
    public string Name { get; set; }
    public virtual Uri SiteUri { get; set; }

    public ICollection<Post> Posts { get; }
}
public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }
    public DateTime PublishedOn { get; set; }
    public bool Archived { get; set; }

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

Conseil

Les propriétés de clé primaire et étrangère du type d’entité n’ont pas besoin d’être des propriétés visibles publiquement. Toutefois, même lorsque les propriétés sont masquées, il est important de considérer qu’elles existent toujours dans le modèle EF.

La propriété de clé primaire de Blog, Blog.Id, et la propriété de clé étrangère de Post, Post.BlogId, peuvent ensuite être associées aux références (« navigations ») entre les types d’entité (Blog.Posts et Post.Blog). Cette opération est effectuée automatiquement par EF lors de la création d’une relation simple comme celle-ci, mais elle peut également être spécifiée explicitement lors de la substitution de la méthode OnModelCreating de votre DbContext. Par exemple :

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder.Entity<Blog>()
        .HasMany(e => e.Posts)
        .WithOne(e => e.Blog)
        .HasForeignKey(e => e.BlogId)
        .HasPrincipalKey(e => e.Id);
}

Désormais, toutes ces propriétés se comportent de manière cohérente entre elles, comme la représentation d’une relation unique entre Blog et Post.

En savoir plus

EF prend en charge beaucoup d’autres types de relations, avec différentes possibilités de représenter et de configurer ces relations. Pour accéder à différents types de relations, consultez les exemples suivants :

Si vous débutez avec EF, essayer les exemples liés dans la liste ci-dessus est un bon moyen pour comprendre le fonctionnement des relations.

Pour aller plus loin dans les propriétés des types d’entités impliquées dans le mappage des relations, consultez :

Les modèles EF sont conçus à l’aide d’une combinaison de trois mécanismes : conventions, attributs de mappage et API du générateur de modèles. L’API de génération de modèles apparaît dans la plupart des exemples. Pour en savoir plus sur d’autres options, consultez :

  • Conventions de relation, qui identifie les types d’entités, leurs propriétés et les relations entre les types.
  • Attributs de mappage de relation, qui peuvent être utilisés comme une alternative à l’API de génération de modèles pour certains aspects de la configuration des relations.

Important

L’API de génération de modèles reste définitivement la source de référence pour le modèle EF : elle est toujours prioritaire sur la configuration définie par convention ou spécifiée par les attributs de mappage. Il s’agit également du seul mécanisme totalement fiable pour configurer chaque aspect du modèle EF.

Voici d’autres rubriques liées aux relations :

  • Suppressions en cascade, qui décrit comment les entités associées peuvent être automatiquement supprimées quand SaveChanges ou SaveChangesAsync est appelée.
  • Les types d’entité détenues utilisent un type spécial de relation « propriétaire » qui implique une connexion plus forte entre les deux types que les relations « normales » décrites ici. Bon nombre des concepts décrits ici pour les relations normales sont applicables aux relations détenues. Toutefois, les relations détenues ont également leurs propres comportements spécifiques.

Conseil

Reportez-vous si nécessaire au glossaire des relations pendant la lecture de la documentation. Cela vous aidera à mieux comprendre la terminologie utilisée.

Utilisation des relations

Les relations définies dans le modèle peuvent être utilisées de manières diverses. Par exemple :