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 Post
sur 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 Blogs
Id
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 BlogId
de Posts
doit 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 :
- Relations un-à-plusieurs, utilisées lorsqu’une entité unique est associée à un nombre quelconque d’autres entités.
- Relations un-à-un, dans lesquelles une entité unique est associée à une autre entité unique.
- Relations plusieurs-à-plusieurs, dans lesquelles un nombre quelconque d’entités sont associées à un nombre quelconque d’autres entités.
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 :
- Clés étrangères et principales dans les relations, qui aborde la manière dont les clés étrangères sont mappées à la base de données.
- Navigations pour la relation, qui décrit comment les navigations sont superposées sur une clé étrangère pour fournir une vue orientée objet de la relation.
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
ouSaveChangesAsync
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 :
- Les relations peuvent servir à interroger les données associées de trois façons :
- En mode hâtif, dans le cadre d’une requête LINQ, en utilisant
Include
. - En mode différé, à l’aide de proxys de chargement différé, ou des chargement différés sans proxys.
- Avec un chargement explicite, en utilisant les méthodes
Load
ouLoadAsync
.
- En mode hâtif, dans le cadre d’une requête LINQ, en utilisant
- Les relations peuvent être appliquées pour l’amorçage des données par le biais de la correspondance de valeurs PK avec des valeurs FK.
- Les relations peuvent permettre de suivre les graphiques d’entités. Les relations sont ensuite utilisées par le suivi des modifications pour :
- détecter les modifications apportées aux relations et effectuer des correctifs
- envoyer des mises à jour de clé étrangère à la base de données avec
SaveChanges
ouSaveChangesAsync