Partager via


Suppression en cascade

Entity Framework Core (EF Core) représente les relations à l’aide de clés étrangères. Une entité avec une clé étrangère est l’entité enfant ou dépendante dans la relation. La valeur de clé étrangère de cette entité doit correspondre à la valeur de clé primaire (ou à une autre valeur de clé) de l’entité principale/parente associée.

Si l’entité principale/parente est supprimée, les valeurs de clé étrangère des entités dépendantes/enfants ne correspondent plus à la clé primaire ou à la clé alternative d’une entité principale/parente. Il s’agit d’un état non valide, qui entraîne une violation de contrainte référentielle dans la plupart des bases de données.

Il existe deux options pour éviter cette violation de contrainte référentielle :

  1. Affecter la valeur null aux valeurs de clé étrangère
  2. Supprimer également les entités dépendantes/enfants

La première option est valide uniquement pour les relations facultatives où la propriété de clé étrangère (et la colonne de base de données à laquelle elle est mappée) doit être nullable.

La deuxième option est valide pour tous les genres de relations, et est appelée « suppression en cascade ».

Conseil

Ce document décrit les suppressions en cascade (et la suppression des orphelins) dans la perspective de la mise à jour de la base de données. Il utilise fréquemment les concepts introduits dans Suivi des modifications dans EF Core et Modification des clés étrangères et des navigations. Veillez à bien comprendre ces concepts avant d’aborder le contenu présenté ici.

Conseil

Vous pouvez exécuter et déboguer dans tout le code de ce document en téléchargeant l’exemple de code à partir de GitHub.

Quand se produisent les comportements en cascade

Les suppressions en cascade sont nécessaires quand une entité dépendante/enfant ne peut plus être associée à son entité principale/parente actuelle. Cela peut se produire à la suite de la suppression de l’entité principale/parente, ou quand l’entité principale/parente existe toujours mais que l’entité dépendante/enfant ne lui est plus associée.

Suppression d’une entité principale/parente

Prenons ce modèle simple où Blog est l’entité principale/parente dans une relation avec Post, qui est l’entité dépendante/enfant. Post.BlogId est une propriété de clé étrangère, dont la valeur doit correspondre à la clé primaire Blog.Id du blog auquel le billet appartient.

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

    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();
}

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

    public string Title { get; set; }
    public string Content { get; set; }

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

Par convention, cette relation est configurée comme étant obligatoire, car la propriété de clé étrangère Post.BlogId est non-nullable. Les relations obligatoires sont configurées pour utiliser les suppressions en cascade par défaut. Pour plus d’informations sur la modélisation des relations, consultez Relations.

Quand vous supprimez un blog, tous les billets sont supprimés en cascade. Par exemple :

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

context.Remove(blog);

context.SaveChanges();

SaveChanges génère le code SQL suivant, en prenant SQL Server comme exemple :

-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Rupture d’une relation

Au lieu de supprimer le blog, nous pouvons rompre la relation entre chaque billet et son blog. Pour ce faire, affectez la valeur null à la navigation de référence Post.Blog pour chaque billet :

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

context.SaveChanges();

Vous pouvez également rompre la relation en supprimant chaque billet de la navigation dans la collection Blog.Posts :

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

blog.Posts.Clear();

context.SaveChanges();

Dans les deux cas, le résultat est le même : le blog n’est pas supprimé, mais les billets qui ne sont plus associés à un blog sont supprimés :

-- Executed DbCommand (1ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p0='2'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Posts]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

La suppression d’entités qui ne sont plus associées à une entité principale/dépendante s’appelle la « suppression des orphelins ».

Conseil

La suppression en cascade et la suppression des orphelins sont étroitement liées. Les deux entraînent la suppression des entités dépendantes/enfants quand la relation avec leur entité principale/parente obligatoire est rompue. Dans le cas de la suppression en cascade, cette rupture se produit dans la mesure où l’entité principale/parente est elle-même supprimée. Dans le cas des orphelins, l’entité principale/parente existe toujours, mais elle n’est plus liée aux entités dépendantes/enfants.

Où se produisent les comportements en cascade

Les comportements en cascade peuvent s’appliquer aux :

  • Entités suivies par le DbContext actuel
  • Entités de la base de données qui n’ont pas été chargées dans le contexte

Suppression en cascade d’entités suivies

EF Core applique toujours les comportements en cascade configurés aux entités suivies. Cela signifie que si l’application charge toutes les entités dépendantes/enfants appropriées dans DbContext, comme indiqué dans les exemples ci-dessus, les comportements en cascade sont correctement appliqués, quelle que soit la configuration de la base de données.

Conseil

Le moment exact où les comportements en cascade se produisent pour les entités suivies peut être contrôlé à l’aide de ChangeTracker.CascadeDeleteTiming et ChangeTracker.DeleteOrphansTiming. Pour plus d’informations, consultez Modification des clés étrangères et des navigations.

Suppression en cascade dans la base de données

De nombreux systèmes de base de données proposent également des comportements en cascade qui se déclenchent quand une entité est supprimée dans la base de données. EF Core configure ces comportements en fonction du comportement de suppression en cascade du modèle EF Core quand une base de données est créée à l’aide de EnsureCreated ou des migrations EF Core. Par exemple, à l’aide du modèle ci-dessus, la table suivante est créée pour les billets quand vous utilisez SQL Server :

CREATE TABLE [Posts] (
    [Id] int NOT NULL IDENTITY,
    [Title] nvarchar(max) NULL,
    [Content] nvarchar(max) 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
);

Notez que la contrainte de clé étrangère définissant la relation entre les blogs et les billets est configurée avec ON DELETE CASCADE.

Si nous savons que la base de données est configurée de cette façon, nous pouvons supprimer un blog sans charger au préalable les billets. La base de données s’occupe de supprimer tous les billets liés à ce blog. Par exemple :

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).First();

context.Remove(blog);

context.SaveChanges();

Notez qu’il n’existe pas de Include pour les billets. Ils ne sont donc pas chargés. Dans ce cas, SaveChanges supprime uniquement le blog, car il s’agit de la seule entité faisant l’objet d’un suivi :

-- Executed DbCommand (6ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

Cela entraîne une exception si la contrainte de clé étrangère dans la base de données n’est pas configurée pour les suppressions en cascade. Toutefois, dans ce cas, les billets sont supprimés par la base de données, car elle a été configurée avec ON DELETE CASCADE au moment de sa création.

Remarque

En règle générale, les bases de données n’ont aucun moyen de supprimer automatiquement les orphelins. En effet, bien qu’EF Core représente les relations à l’aide de navigations et de clés étrangères, les bases de données ont uniquement des clés étrangères, et aucune navigation. Cela signifie qu’il n’est généralement pas possible de rompre une relation sans charger les deux côtés dans DbContext.

Remarque

Pour le moment, la base de données en mémoire EF Core ne prend pas en charge les suppressions en cascade dans la base de données.

Avertissement

Ne configurez pas la suppression en cascade dans la base de données au moment de la suppression réversible d’entités. Cela peut entraîner une suppression réelle accidentelle des entités à la place d’une suppression réversible.

Limitations des comportements en cascade dans les bases de données

Certaines bases de données, plus particulièrement SQL Server, ont des limitations pour les comportements en cascade qui forment les cycles. Par exemple, prenons le modèle suivant :

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

    public IList<Post> Posts { get; } = new List<Post>();

    public int OwnerId { get; set; }
    public Person Owner { get; set; }
}

public class Post
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Content { get; set; }

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

    public int AuthorId { get; set; }
    public Person Author { get; set; }
}

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }

    public IList<Post> Posts { get; } = new List<Post>();

    public Blog OwnedBlog { get; set; }
}

Ce modèle a trois relations, toutes obligatoires, et donc configurées pour la suppression en cascade par convention :

  • La suppression d’un blog entraîne la suppression en cascade de tous les billets associés
  • La suppression de l’auteur des billets entraîne la suppression en cascade des billets créés
  • La suppression du propriétaire d’un blog entraîne la suppression en cascade du blog

Tout cela est raisonnable (bien qu’un peu draconien dans le cadre des stratégies de gestion de blogs), mais la tentative de création d’une base de données SQL Server avec la configuration de ces cascades entraîne l’exception suivante :

Microsoft.Data.SqlClient.SqlException (0x80131904) : L’introduction de la contrainte FOREIGN KEY « FK_Posts_Person_AuthorId » sur la table « Posts » peut entraîner des problèmes de références cycliques ou de chemins en cascade multiples. Spécifiez ON DELETE NO ACTION ou ON UPDATE NO ACTION, ou modifiez d'autres contraintes FOREIGN KEY.

Il existe deux façons de gérer cette situation :

  1. Changez une ou plusieurs des relations pour ne pas effectuer de suppressions en cascade.
  2. Configurez la base de données sans une ou plusieurs de ces suppressions en cascade, puis vérifiez que toutes les entités dépendantes sont chargées pour qu’EF Core puisse appliquer le comportement en cascade.

En adoptant la première approche avec notre exemple, nous pouvons rendre la relation billet-blog facultative en lui affectant une propriété de clé étrangère nullable :

public int? BlogId { get; set; }

Une relation facultative permet au blog d’exister sans un billet, ce qui signifie que la suppression en cascade ne sera plus configurée par défaut. Cela signifie qu’il n’existe plus de cycle dans les actions en cascade, et que la base de données peut être créée sans erreur sur SQL Server.

En revanche, en adoptant la deuxième approche, nous pouvons maintenir la relation entre le blog et le propriétaire obligatoire, et configurée pour une suppression en cascade, tout en faisant en sorte que cette configuration s’applique uniquement aux entités suivies, et non à la base de données :

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

Que se passe-t-il si nous chargeons à la fois une personne et son blog, et si nous supprimons ensuite cette personne ?

using var context = new BlogsContext();

var owner = context.People.Single(e => e.Name == "ajcvickers");
var blog = context.Blogs.Single(e => e.Owner == owner);

context.Remove(owner);

context.SaveChanges();

EF Core applique la suppression en cascade au propriétaire pour que le blog soit également supprimé :

-- Executed DbCommand (8ms) [Parameters=[@p0='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p0;
SELECT @@ROWCOUNT;

-- Executed DbCommand (2ms) [Parameters=[@p1='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [People]
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Toutefois, si le blog n’est pas chargé au moment de la suppression du propriétaire :

using var context = new BlogsContext();

var owner = context.People.Single(e => e.Name == "ajcvickers");

context.Remove(owner);

context.SaveChanges();

Une exception est levée en raison d’une violation de la contrainte de clé étrangère dans la base de données :

Microsoft.Data.SqlClient.SqlException : L’instruction DELETE est en conflit avec la contrainte REFERENCE « FK_Blogs_People_OwnerId ». Le conflit s’est produit dans la base de données « Scratch », la table « dbo.Blogs », la colonne « OwnerId ». L'instruction a été arrêtée.

Valeurs nulles en cascade

Les relations facultatives ont des propriétés de clé étrangère nullables, mappées à des colonnes de base de données nullables. Cela signifie que la valeur de clé étrangère peut être nulle quand l’entité principale/parente actuelle est supprimée ou séparée de l’entité dépendante/enfant.

Examinons à nouveau les exemples décrits dans la section Quand se produisent les comportements en cascade, mais cette fois avec une relation facultative représentée par une propriété de clé étrangère Post.BlogId nullable :

public int? BlogId { get; set; }

Cette propriété de clé étrangère a la valeur null pour chaque billet quand son blog associé est supprimé. Ce code, par exemple, qui est le même que précédemment :

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

context.Remove(blog);

context.SaveChanges();

Entraîne désormais les mises à jour de base de données suivantes quand SaveChanges est appelé :

-- Executed DbCommand (2ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p1='2', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (1ms) [Parameters=[@p2='1'], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
DELETE FROM [Blogs]
WHERE [Id] = @p2;
SELECT @@ROWCOUNT;

De même, si la relation est rompue à l’aide de l’un des exemples ci-dessus :

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

foreach (var post in blog.Posts)
{
    post.Blog = null;
}

context.SaveChanges();

Ou :

using var context = new BlogsContext();

var blog = context.Blogs.OrderBy(e => e.Name).Include(e => e.Posts).First();

blog.Posts.Clear();

context.SaveChanges();

Les billets sont ensuite mis à jour avec des valeurs de clé étrangère nulles quand SaveChanges est appelé :

-- Executed DbCommand (2ms) [Parameters=[@p1='1', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

-- Executed DbCommand (0ms) [Parameters=[@p1='2', @p0=NULL (DbType = Int32)], CommandType='Text', CommandTimeout='30']
SET NOCOUNT ON;
UPDATE [Posts] SET [BlogId] = @p0
WHERE [Id] = @p1;
SELECT @@ROWCOUNT;

Consultez Modification des clés étrangères et des navigations pour plus d’informations sur la façon dont EF Core gère les clés étrangères et les navigations au fur et à mesure que leurs valeurs changent.

Remarque

La correction des relations de cette façon est le comportement par défaut d’Entity Framework depuis la première version en 2008. Avant EF Core, ce comportement n’avait pas de nom et ne pouvait pas être changé. Il est désormais appelé ClientSetNull, comme indiqué dans la section suivante.

Les bases de données peuvent également être configurées pour utiliser des valeurs nulles en cascade de cette façon, quand une entité principale/parente d’une relation facultative est supprimée. Toutefois, il s’agit d’une opération beaucoup moins courante que l’utilisation de suppressions en cascade dans la base de données. L’utilisation simultanée de suppressions en cascade et de valeurs nulles en cascade dans la base de données entraîne presque toujours l’apparition de problèmes de cycles dans les relations quand SQL Server est utilisé. Pour plus d’informations sur la configuration des valeurs nulles en cascade, consultez la section suivante.

Configuration des comportements en cascade

Conseil

Veillez à lire les sections ci-dessus avant de poursuivre la lecture de ce contenu. Les options de configuration n’auront probablement aucun sens si les informations précédentes ne sont pas comprises.

Les comportements en cascade sont configurés par relation à l’aide de la méthode OnDelete dans OnModelCreating. Par exemple :

protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    modelBuilder
        .Entity<Blog>()
        .HasOne(e => e.Owner)
        .WithOne(e => e.OwnedBlog)
        .OnDelete(DeleteBehavior.ClientCascade);
}

Pour plus d’informations sur la configuration des relations entre les types d’entités, consultez Relations.

OnDelete accepte une valeur provenant de l’enum DeleteBehavior, qui prête parfois à confusion. Cet enum définit à la fois le comportement d’EF Core sur les entités suivies ainsi que la configuration de la suppression en cascade dans la base de données quand EF est utilisé pour créer le schéma.

Impact sur le schéma de base de données

Le tableau suivant montre le résultat de chaque valeur OnDelete sur la contrainte de clé étrangère créée par les migrations EF Core ou EnsureCreated.

DeleteBehavior Impact sur le schéma de base de données
En cascade ON DELETE CASCADE
Restreindre ON DELETE RESTRICT
NoAction comportement par défaut de la base de données
SetNull ON DELETE SET NULL
ClientSetNull comportement par défaut de la base de données
ClientCascade comportement par défaut de la base de données
ClientNoAction comportement par défaut de la base de données

Les comportements de ON DELETE NO ACTION (comportement par défaut de la base de données) et de ON DELETE RESTRICT dans les bases de données relationnelles sont généralement identiques ou très similaires. Malgré ce que NO ACTION peut impliquer, ces deux options entraînent l’application de contraintes référentielles. La différence, quand elle existe, réside dans le moment où la base de données vérifie les contraintes. Consultez la documentation de votre base de données pour connaître les différences spécifiques entre ON DELETE NO ACTION et ON DELETE RESTRICT au sein de votre système de base de données.

SQL Server ne prend pas en charge ON DELETE RESTRICT. ON DELETE NO ACTION est donc utilisé à la place.

Les seules valeurs qui entraînent des comportements en cascade dans la base de données sont Cascade et SetNull. Toutes les autres valeurs permettent de configurer la base de données pour qu’aucun changement ne soit effectué en cascade.

Impact sur le comportement de SaveChanges

Les tableaux des sections suivantes décrivent ce qui arrive aux entités dépendantes/enfants quand l’entité principale/parente est supprimée, ou quand sa relation avec les entités dépendantes/enfants est rompue. Chaque tableau décrit l’un des aspects suivants :

  • Relations facultatives (clé étrangère nullable) et obligatoires (clé étrangère non-nullable)
  • Moment où les entités dépendantes/enfants sont chargées et suivies par DbContext, et moment où elles existent uniquement dans la base de données

Relation obligatoire avec les entités dépendantes/enfants chargées

DeleteBehavior Au moment de la suppression de l’entité principale/parente Au moment de la rupture par rapport à l’entité principale/parente
En cascade Entités dépendantes supprimées par EF Core Entités dépendantes supprimées par EF Core
Restreindre InvalidOperationException InvalidOperationException
NoAction InvalidOperationException InvalidOperationException
SetNull SqlException au moment de la création de la base de données SqlException au moment de la création de la base de données
ClientSetNull InvalidOperationException InvalidOperationException
ClientCascade Entités dépendantes supprimées par EF Core Entités dépendantes supprimées par EF Core
ClientNoAction DbUpdateException InvalidOperationException

Remarques :

  • La valeur par défaut pour les relations obligatoires de ce genre est Cascade.
  • L’utilisation d’un autre comportement que la suppression en cascade pour les relations obligatoires entraîne une exception quand SaveChanges est appelé.
    • En règle générale, il s’agit d’une exception InvalidOperationException d’EF Core, car l’état non valide est détecté dans les entités enfants/dépendantes chargées.
    • ClientNoAction force EF Core à ne pas vérifier les entités dépendantes avant de les envoyer à la base de données. Dans ce cas, la base de données lève une exception, qui est ensuite wrappée dans DbUpdateException par SaveChanges.
    • SetNull est rejeté au moment de la création de la base de données, car la colonne de clé étrangère est non-nullable.
  • Dans la mesure où les entités dépendantes/enfants sont chargées, elles sont toujours supprimées par EF Core, et jamais par la base de données.

Relation obligatoire avec les entités dépendantes/enfants non chargées

DeleteBehavior Au moment de la suppression de l’entité principale/parente Au moment de la rupture par rapport à l’entité principale/parente
En cascade Entités dépendantes supprimées par la base de données S.O.
Restreindre DbUpdateException S.O.
NoAction DbUpdateException S.O.
SetNull SqlException au moment de la création de la base de données S.O.
ClientSetNull DbUpdateException S.O.
ClientCascade DbUpdateException S.O.
ClientNoAction DbUpdateException S.O.

Remarques :

  • La rupture d’une relation n’est pas valide ici, car les entités dépendantes/enfants ne sont pas chargées.
  • La valeur par défaut pour les relations obligatoires de ce genre est Cascade.
  • L’utilisation d’un autre comportement que la suppression en cascade pour les relations obligatoires entraîne une exception quand SaveChanges est appelé.
    • En règle générale, il s’agit d’une exception DbUpdateException, car les entités dépendantes/enfants ne sont pas chargées. L’état non valide ne peut donc être détecté que par la base de données. SaveChanges wrappe ensuite l’exception de base de données dans DbUpdateException.
    • SetNull est rejeté au moment de la création de la base de données, car la colonne de clé étrangère est non-nullable.

Relation facultative avec les entités dépendantes/enfants chargées

DeleteBehavior Au moment de la suppression de l’entité principale/parente Au moment de la rupture par rapport à l’entité principale/parente
En cascade Entités dépendantes supprimées par EF Core Entités dépendantes supprimées par EF Core
Restreindre Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core
NoAction Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core
SetNull Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core
ClientSetNull Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core
ClientCascade Entités dépendantes supprimées par EF Core Entités dépendantes supprimées par EF Core
ClientNoAction DbUpdateException Clés étrangères d’entités dépendantes ayant une valeur null affectée par EF Core

Remarques :

  • La valeur par défaut pour les relations facultatives de ce genre est ClientSetNull.
  • Les entités dépendantes/enfants ne sont jamais supprimées, sauf si Cascade ou ClientCascade sont configurés.
  • Toutes les autres valeurs entraînent l’affectation de la valeur null aux clés étrangères d’entités dépendantes par EF Core...
    • ...à l’exception de ClientNoAction, qui indique à EF Core de ne pas toucher aux clés étrangères des entités dépendantes/enfants quand l’entité principale/parente est supprimée. La base de données lève donc une exception, qui est wrappée en tant que DbUpdateException par SaveChanges.

Relation facultative avec les entités dépendantes/enfants non chargées

DeleteBehavior Au moment de la suppression de l’entité principale/parente Au moment de la rupture par rapport à l’entité principale/parente
En cascade Entités dépendantes supprimées par la base de données S.O.
Restreindre DbUpdateException S.O.
NoAction DbUpdateException S.O.
SetNull Clés étrangères d’entités dépendantes ayant une valeur null affectée par la base de données S.O.
ClientSetNull DbUpdateException S.O.
ClientCascade DbUpdateException S.O.
ClientNoAction DbUpdateException S.O.

Remarques :

  • La rupture d’une relation n’est pas valide ici, car les entités dépendantes/enfants ne sont pas chargées.
  • La valeur par défaut pour les relations facultatives de ce genre est ClientSetNull.
  • Les entités dépendantes/enfants doivent être chargées pour éviter une exception de base de données, sauf si la base de données a été configurée pour mettre en cascade les suppressions ou les valeurs nulles.