Suppression en cascadeCascade Delete

La suppression en cascade est couramment utilisée dans la terminologie de base de données pour décrire une caractéristique qui permet à la suppression d’une ligne de déclencher automatiquement la suppression de lignes associées.Cascade delete is commonly used in database terminology to describe a characteristic that allows the deletion of a row to automatically trigger the deletion of related rows. Un concept étroitement lié également couvert par les comportements de suppression d’EF cœur est la suppression automatique d’une entité enfant lorsque sa relation à un parent a été interrompue. Cela est communément appelé « suppression des orphelins ».A closely related concept also covered by EF Core delete behaviors is the automatic deletion of a child entity when it's relationship to a parent has been severed--this is commonly known as "deleting orphans".

EF Core implémente plusieurs comportements de suppression différents et permet la configuration de comportements de suppression de relations individuelles.EF Core implements several different delete behaviors and allows for the configuration of the delete behaviors of individual relationships. EF Core implémente également des conventions qui configurent automatiquement les comportements de suppression par défaut utiles pour chaque relation en fonction de la nécessité de la relation.EF Core also implements conventions that automatically configure useful default delete behaviors for each relationship based on the requiredness of the relationship.

Comportements de suppressionDelete behaviors

Les comportements de suppression sont définis dans le type énumérateur deleteBehavior() et peuvent être passés à l’API Fluent OnDelete pour contrôler si la suppression d’une entité principale/parente ou l’interruption de la relation avec les entités dépendantes/enfant doit avoir un effet secondaire sur les entités dépendantes/enfant.Delete behaviors are defined in the DeleteBehavior enumerator type and can be passed to the OnDelete fluent API to control whether the deletion of a principal/parent entity or the severing of the relationship to dependent/child entities should have a side effect on the dependent/child entities.

Il existe trois mesures qu'EF peut prendre lorsqu’une entité principale/parent est supprimée ou que la relation avec l’enfant est interrompue :There are three actions EF can take when a principal/parent entity is deleted or the relationship to the child is severed:

  • L’entité dépendante/enfant peut être suppriméeThe child/dependent can be deleted
  • Les valeurs de clé étrangère de l’enfant peuvent être définies avec la valeur nullThe child's foreign key values can be set to null
  • L’enfant reste inchangéThe child remains unchanged

Note

Le comportement de suppression configuré dans le modèle EF Core est uniquement appliqué lorsque l’entité principale est supprimée à l’aide d’EF Core et que les entités dépendantes sont chargées en mémoire (par exemple, pour les suivis dépendants).The delete behavior configured in the EF Core model is only applied when the principal entity is deleted using EF Core and the dependent entities are loaded in memory (that is, for tracked dependents). Un comportement de cascade correspondant doit être configuré dans la base de données pour s’assurer que les données qui ne sont pas suivies par le contexte disposent de la bonne action appliquée.A corresponding cascade behavior needs to be setup in the database to ensure data that is not being tracked by the context has the necessary action applied. Si vous utilisez EF Core pour créer la base de données, ce comportement en cascade sera configuré pour vous.If you use EF Core to create the database, this cascade behavior will be setup for you.

Pour la deuxième action ci-dessus, la définition d’une clé étrangère sur la valeur null n’est pas valide si cette clé étrangère n’accepte pas la valeur null.For the second action above, setting a foreign key value to null is not valid if foreign key is not nullable. (Une clé étrangère n’acceptant pas la valeur null est équivalente à une relation requise.) Dans ces cas, EF Core note que la propriété de clé étrangère a été marquée comme null jusqu'à l’appel à SaveChanges, auquel cas une exception est levée, car la modification ne peut pas être conservée dans la base de données.(A non-nullable foreign key is equivalent to a required relationship.) In these cases, EF Core tracks that the foreign key property has been marked as null until SaveChanges is called, at which time an exception is thrown because the change cannot be persisted to the database. Cela est similaire à une violation de contrainte de la base de données.This is similar to getting a constraint violation from the database.

Il existe quatre comportements de suppression, répertoriés dans les tableaux ci-dessous.There are four delete behaviors, as listed in the tables below.

Relations facultativesOptional relationships

Pour les relations facultatives (clé étrangère acceptant la valeur null) il est possible d’enregistrer une valeur null de clé étrangère, ce qui entraîne les conséquences suivantes :For optional relationships (nullable foreign key) it is possible to save a null foreign key value, which results in the following effects:

Nom du comportementBehavior Name Effet sur les entités dépendantes/enfant en mémoireEffect on dependent/child in memory Effet sur les entités dépendantes/enfant dans la base de donnéesEffect on dependent/child in database
CascadeCascade Les entités sont suppriméesEntities are deleted Les entités sont suppriméesEntities are deleted
ClientSetNull (par défaut)ClientSetNull (Default) Les propriétés de clé étrangère sont définies avec la valeur nullForeign key properties are set to null Aucun.None
SetNullSetNull Les propriétés de clé étrangère sont définies avec la valeur nullForeign key properties are set to null Les propriétés de clé étrangère sont définies avec la valeur nullForeign key properties are set to null
RestrictRestrict Aucun.None Aucun.None

Relations requisesRequired relationships

Pour les relations requises (clé étrangère n’acceptant pas la valeur null) il n’est pas possible d’enregistrer une valeur null de clé étrangère, ce qui entraîne les conséquences suivantes :For required relationships (non-nullable foreign key) it is not possible to save a null foreign key value, which results in the following effects:

Nom du comportementBehavior Name Effet sur les entités dépendantes/enfant en mémoireEffect on dependent/child in memory Effet sur les entités dépendantes/enfant dans la base de donnéesEffect on dependent/child in database
Cascade (par défaut)Cascade (Default) Les entités sont suppriméesEntities are deleted Les entités sont suppriméesEntities are deleted
ClientSetNullClientSetNull Lève une exception SaveChangesSaveChanges throws Aucun.None
SetNullSetNull Lève une exception SaveChangesSaveChanges throws Lève une exception SaveChangesSaveChanges throws
RestrictRestrict Aucun.None Aucun.None

Dans les tableaux ci-dessus, Aucun peut entraîner une violation de contrainte.In the tables above, None can result in a constraint violation. Par exemple, si une entité principale/enfant est supprimée, mais qu’aucune action n’est effectuée pour modifier la clé étrangère d’une entité dépendante/enfant, la base de données lèvera probablement une exception sur SaveChanges en raison d’une violation de contrainte étrangère.For example, if a principal/child entity is deleted but no action is taken to change the foreign key of a dependent/child, then the database will likely throw on SaveChanges due to a foreign constraint violation.

À un niveau élevé :At a high level:

  • Si vous avez des entités qui ne peuvent pas exister sans un parent, et que vous souhaitez qu’EF se charge de la suppression des enfants automatiquement, utilisez Cascade.If you have entities that cannot exist without a parent, and you want EF to take care for deleting the children automatically, then use Cascade.
    • Les entités qui ne peuvent pas exister sans un parent utilisent généralement les relations requises, dont Cascade est la valeur par défaut.Entities that cannot exist without a parent usually make use of required relationships, for which Cascade is the default.
  • Si vous avez des entités qui peuvent ou ne peuvent pas avoir un parent, et que vous souhaitez qu’EF prenne en charge la définition de la clé étrangère sur null pour vous, utilisez ClientSetNullIf you have entities that may or may not have a parent, and you want EF to take care of nulling out the foreign key for you, then use ClientSetNull
    • Les entités qui peuvent exister sans un parent utilisent généralement les relations optionnelles, dont ClientSetNull est la valeur par défaut.Entities that can exist without a parent usually make use of optional relationships, for which ClientSetNull is the default.
    • Si vous souhaitez que la base de données essaye également de propager les valeurs null aux clés étrangères enfant même lorsque l’entité enfant n’est pas chargée, utilisez SetNull.If you want the database to also try to propagate null values to child foreign keys even when the child entity is not loaded, then use SetNull. Toutefois, notez que la base de données doit prendre en charge cela, et que la configuration de la base de données de cette façon peut entraîner d’autres restrictions, qui dans la pratique rendent souvent cette option inappropriée.However, note that the database must support this, and configuring the database like this can result in other restrictions, which in practice often makes this option impractical. C’est pourquoi SetNull n’est pas la valeur par défaut.This is why SetNull is not the default.
  • Si vous souhaitez qu’EF Core ne supprime jamais une entité automatiquement ou règle automatiquement la clé étrangère sur null, utilisez Restrict.If you don't want EF Core to ever delete an entity automatically or null out the foreign key automatically, then use Restrict. Notez que dans ce cas votre code doit synchroniser les entités enfant et leurs valeurs de clé étrangère manuellement. Dans le cas contraire des exceptions de contrainte seront levées.Note that this requires that your code keep child entities and their foreign key values in sync manually otherwise constraint exceptions will be thrown.

Note

Dans EF Core, contrairement à EF6, les effets en cascade ne se produisent pas immédiatement, mais à la place uniquement lorsque SaveChanges est appelé.In EF Core, unlike EF6, cascading effects do not happen immediately, but instead only when SaveChanges is called.

Note

Changements dans EF Core 2.0 : dans les versions précédentes, Restrict provoquerait la définition des propriétés de clé étrangère facultatives dans des entités dépendantes suivies sur null. C’était le comportement de suppression par défaut pour les relations optionnelles.Changes in EF Core 2.0: In previous releases, Restrict would cause optional foreign key properties in tracked dependent entities to be set to null, and was the default delete behavior for optional relationships. Dans EF Core 2.0, l’option ClientSetNull a été introduite pour représenter ce comportement et est devenue la valeur par défaut pour les relations facultatives.In EF Core 2.0, the ClientSetNull was introduced to represent that behavior and became the default for optional relationships. Le comportement de Restrict a été ajusté pour ne jamais avoir d’effets sur les entités dépendantes.The behavior of Restrict was adjusted to never have any side effects on dependent entities.

Exemples de suppression d’entitéEntity deletion examples

Le code suivant fait partie d’un exemple qui peut être téléchargé et exécuté.The code below is part of a sample that can be downloaded and run. L’exemple montre ce qui se passe pour chaque comportement de suppression pour les relations facultatives et requises lorsqu’une entité parente est supprimée.The sample shows what happens for each delete behavior for both optional and required relationships when a parent entity is deleted.

var blog = context.Blogs.Include(b => b.Posts).First();
var posts = blog.Posts.ToList();

DumpEntities("  After loading entities:", context, blog, posts);

context.Remove(blog);

DumpEntities($"  After deleting blog '{blog.BlogId}':", context, blog, posts);

try
{
    Console.WriteLine();
    Console.WriteLine("  Saving changes:");

    context.SaveChanges();

    DumpSql();

    DumpEntities("  After SaveChanges:", context, blog, posts);
}
catch (Exception e)
{
    DumpSql();

    Console.WriteLine();
    Console.WriteLine($"  SaveChanges threw {e.GetType().Name}: {(e is DbUpdateException ? e.InnerException.Message : e.Message)}");
}

Nous allons étudier chaque variation de comprendre ce qui se passe.Let's walk through each variation to understand what is happening.

DeleteBehavior.Cascade avec une relation obligatoire ou facultativeDeleteBehavior.Cascade with required or optional relationship

  After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After deleting blog '1':
    Blog '1' is in state Deleted with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  Saving changes:
    DELETE FROM [Posts] WHERE [PostId] = 1
    DELETE FROM [Posts] WHERE [PostId] = 2
    DELETE FROM [Blogs] WHERE [BlogId] = 1

  After SaveChanges:
    Blog '1' is in state Detached with 2 posts referenced.
      Post '1' is in state Detached with FK '1' and no reference to a blog.
      Post '2' is in state Detached with FK '1' and no reference to a blog.
  • Le blog est marqué comme suppriméBlog is marked as Deleted
  • Les billets restent initialement inchangés étant donné que les cascades ne se produisent pas avant SaveChangesPosts initially remain Unchanged since cascades do not happen until SaveChanges
  • SaveChanges envoie des suppressions pour les entités dépendantes/enfant (les billets), puis pour l’entité principale/parent (le blog)SaveChanges sends deletes for both dependents/children (posts) and then the principal/parent (blog)
  • Après l’enregistrement, toutes les entités sont détachées, car elles ont été supprimées de la base de donnéesAfter saving, all entities are detached since they have now been deleted from the database

DeleteBehavior.ClientSetNull ou DeleteBehavior.SetNull avec une relation requiseDeleteBehavior.ClientSetNull or DeleteBehavior.SetNull with required relationship

  After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After deleting blog '1':
    Blog '1' is in state Deleted with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  Saving changes:
    UPDATE [Posts] SET [BlogId] = NULL WHERE [PostId] = 1

  SaveChanges threw DbUpdateException: Cannot insert the value NULL into column 'BlogId', table 'EFSaving.CascadeDelete.dbo.Posts'; column does not allow nulls. UPDATE fails. The statement has been terminated.
  • Le blog est marqué comme suppriméBlog is marked as Deleted
  • Les billets restent initialement inchangés étant donné que les cascades ne se produisent pas avant SaveChangesPosts initially remain Unchanged since cascades do not happen until SaveChanges
  • SaveChanges tente de définir la clé étrangère du billet sur null, mais cette opération échoue car la clé étrangère ne peut pas avoir la valeur nullSaveChanges attempts to set the post FK to null, but this fails because the FK is not nullable

DeleteBehavior.ClientSetNull ou DeleteBehavior.SetNull avec une relation facultativeDeleteBehavior.ClientSetNull or DeleteBehavior.SetNull with optional relationship

  After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After deleting blog '1':
    Blog '1' is in state Deleted with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  Saving changes:
    UPDATE [Posts] SET [BlogId] = NULL WHERE [PostId] = 1
    UPDATE [Posts] SET [BlogId] = NULL WHERE [PostId] = 2
    DELETE FROM [Blogs] WHERE [BlogId] = 1

  After SaveChanges:
    Blog '1' is in state Detached with 2 posts referenced.
      Post '1' is in state Unchanged with FK 'null' and no reference to a blog.
      Post '2' is in state Unchanged with FK 'null' and no reference to a blog.
  • Le blog est marqué comme suppriméBlog is marked as Deleted
  • Les billets restent initialement inchangés étant donné que les cascades ne se produisent pas avant SaveChangesPosts initially remain Unchanged since cascades do not happen until SaveChanges
  • SaveChanges tente de définir clé étrangère des entités dépendantes/enfant (les billets) sur null avant de supprimer l’entité principale/parent (le blog)SaveChanges attempts sets the FK of both dependents/children (posts) to null before deleting the principal/parent (blog)
  • Après l’enregistrement, l’entité principale/parent (le blog) est supprimée, mais les entités dépendantes/enfant (les billets) sont toujours suiviesAfter saving, the principal/parent (blog) is deleted, but the dependents/children (posts) are still tracked
  • Les entités dépendantes/enfant suivies (les billets) ont maintenant des valeurs de clé étrangère null et leur référence à l’entité principale/parent (le blog) a été suppriméeThe tracked dependents/children (posts) now have null FK values and their reference to the deleted principal/parent (blog) has been removed

DeleteBehavior.Restrict avec une relation obligatoire ou facultativeDeleteBehavior.Restrict with required or optional relationship

  After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After deleting blog '1':
    Blog '1' is in state Deleted with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  Saving changes:
  SaveChanges threw InvalidOperationException: The association between entity types 'Blog' and 'Post' has been severed but the foreign key for this relationship cannot be set to null. If the dependent entity should be deleted, then setup the relationship to use cascade deletes.
  • Le blog est marqué comme suppriméBlog is marked as Deleted
  • Les billets restent initialement inchangés étant donné que les cascades ne se produisent pas avant SaveChangesPosts initially remain Unchanged since cascades do not happen until SaveChanges
  • Étant donné que Restrict indique à EF de ne pas automatiquement définir la clé étrangère sur null, elle reste non null et SaveChanges lève une exception sans enregistrerSince Restrict tells EF to not automatically set the FK to null, it remains non-null and SaveChanges throws without saving

Exemples de suppression d’orphelinsDelete orphans examples

Le code suivant fait partie d’un exemple qui peut être téléchargé et exécuté.The code below is part of a sample that can be downloaded and run. L’exemple montre ce qui se passe pour chaque comportement de suppression pour les relations facultatives et requises lorsque la relation entre une entité principale/parent et ses entités dépendantes/enfant est interrompue.The sample shows what happens for each delete behavior for both optional and required relationships when the relationship between a parent/principal and its children/dependents is severed. Dans cet exemple, la relation est rompue en supprimant les entités dépendantes/enfant (les billets) de la propriété de navigation de collection sur l’entité principale/parent (le blog).In this example, the relationship is severed by removing the dependents/children (posts) from the collection navigation property on the principal/parent (blog). Toutefois, le comportement est le même si la référence de l’entité dépendante/enfant vers l’entité principale/parent est annulée à la place.However, the behavior is the same if the reference from dependent/child to principal/parent is instead nulled out.

var blog = context.Blogs.Include(b => b.Posts).First();
var posts = blog.Posts.ToList();

DumpEntities("  After loading entities:", context, blog, posts);

blog.Posts.Clear();

DumpEntities("  After making posts orphans:", context, blog, posts);

try
{
    Console.WriteLine();
    Console.WriteLine("  Saving changes:");

    context.SaveChanges();

    DumpSql();

    DumpEntities("  After SaveChanges:", context, blog, posts);
}
catch (Exception e)
{
    DumpSql();

    Console.WriteLine();
    Console.WriteLine($"  SaveChanges threw {e.GetType().Name}: {(e is DbUpdateException ? e.InnerException.Message : e.Message)}");
}

Nous allons étudier chaque variation de comprendre ce qui se passe.Let's walk through each variation to understand what is happening.

DeleteBehavior.Cascade avec une relation obligatoire ou facultativeDeleteBehavior.Cascade with required or optional relationship

  After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After making posts orphans:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Modified with FK '1' and no reference to a blog.
      Post '2' is in state Modified with FK '1' and no reference to a blog.

  Saving changes:
    DELETE FROM [Posts] WHERE [PostId] = 1
    DELETE FROM [Posts] WHERE [PostId] = 2

  After SaveChanges:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Detached with FK '1' and no reference to a blog.
      Post '2' is in state Detached with FK '1' and no reference to a blog.
  • Les billets sont marqués comme modifiés, car l’interruption de la relation a provoqué la définition de la clé étrangère sur nullPosts are marked as Modified because severing the relationship caused the FK to be marked as null
    • Si la clé étrangère ne peut pas être null, la valeur réelle ne changera pas même si elle est marquée en tant que valeur nullIf the FK is not nullable, then the actual value will not change even though it is marked as null
  • SaveChanges envoie les suppressions pour les entités dépendantes/enfant (les billets)SaveChanges sends deletes for dependents/children (posts)
  • Après l’enregistrement, les entités dépendantes/enfant (les billets) sont détachées, car elles ont été supprimées de la base de donnéesAfter saving, the dependents/children (posts) are detached since they have now been deleted from the database

DeleteBehavior.ClientSetNull ou DeleteBehavior.SetNull avec une relation requiseDeleteBehavior.ClientSetNull or DeleteBehavior.SetNull with required relationship

  After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After making posts orphans:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Modified with FK 'null' and no reference to a blog.
      Post '2' is in state Modified with FK 'null' and no reference to a blog.

  Saving changes:
    UPDATE [Posts] SET [BlogId] = NULL WHERE [PostId] = 1

  SaveChanges threw DbUpdateException: Cannot insert the value NULL into column 'BlogId', table 'EFSaving.CascadeDelete.dbo.Posts'; column does not allow nulls. UPDATE fails. The statement has been terminated.
  • Les billets sont marqués comme modifiés, car l’interruption de la relation a provoqué la définition de la clé étrangère sur nullPosts are marked as Modified because severing the relationship caused the FK to be marked as null
    • Si la clé étrangère ne peut pas être null, la valeur réelle ne changera pas même si elle est marquée en tant que valeur nullIf the FK is not nullable, then the actual value will not change even though it is marked as null
  • SaveChanges tente de définir la clé étrangère du billet sur null, mais cette opération échoue car la clé étrangère ne peut pas avoir la valeur nullSaveChanges attempts to set the post FK to null, but this fails because the FK is not nullable

DeleteBehavior.ClientSetNull ou DeleteBehavior.SetNull avec une relation facultativeDeleteBehavior.ClientSetNull or DeleteBehavior.SetNull with optional relationship

  After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After making posts orphans:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Modified with FK 'null' and no reference to a blog.
      Post '2' is in state Modified with FK 'null' and no reference to a blog.

  Saving changes:
    UPDATE [Posts] SET [BlogId] = NULL WHERE [PostId] = 1
    UPDATE [Posts] SET [BlogId] = NULL WHERE [PostId] = 2

  After SaveChanges:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK 'null' and no reference to a blog.
      Post '2' is in state Unchanged with FK 'null' and no reference to a blog.
  • Les billets sont marqués comme modifiés, car l’interruption de la relation a provoqué la définition de la clé étrangère sur nullPosts are marked as Modified because severing the relationship caused the FK to be marked as null
    • Si la clé étrangère ne peut pas être null, la valeur réelle ne changera pas même si elle est marquée en tant que valeur nullIf the FK is not nullable, then the actual value will not change even though it is marked as null
  • SaveChanges définit la clé étrangère des entités dépendantes/enfant (billets) sur nullSaveChanges sets the FK of both dependents/children (posts) to null
  • Après enregistrement, les entités dépendantes/enfant suivies (les billets) ont maintenant des valeurs de clé étrangère null et leur référence à l’entité principale/parent (le blog) a été suppriméeAfter saving, the dependents/children (posts) now have null FK values and their reference to the deleted principal/parent (blog) has been removed

DeleteBehavior.Restrict avec une relation obligatoire ou facultativeDeleteBehavior.Restrict with required or optional relationship

  After loading entities:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Unchanged with FK '1' and reference to blog '1'.
      Post '2' is in state Unchanged with FK '1' and reference to blog '1'.

  After making posts orphans:
    Blog '1' is in state Unchanged with 2 posts referenced.
      Post '1' is in state Modified with FK '1' and no reference to a blog.
      Post '2' is in state Modified with FK '1' and no reference to a blog.

  Saving changes:
  SaveChanges threw InvalidOperationException: The association between entity types 'Blog' and 'Post' has been severed but the foreign key for this relationship cannot be set to null. If the dependent entity should be deleted, then setup the relationship to use cascade deletes.
  • Les billets sont marqués comme modifiés, car l’interruption de la relation a provoqué la définition de la clé étrangère sur nullPosts are marked as Modified because severing the relationship caused the FK to be marked as null
    • Si la clé étrangère ne peut pas être null, la valeur réelle ne changera pas même si elle est marquée en tant que valeur nullIf the FK is not nullable, then the actual value will not change even though it is marked as null
  • Étant donné que Restrict indique à EF de ne pas automatiquement définir la clé étrangère sur null, elle reste non null et SaveChanges lève une exception sans enregistrerSince Restrict tells EF to not automatically set the FK to null, it remains non-null and SaveChanges throws without saving

Cascade pour les entités non suiviesCascading to untracked entities

Lorsque vous appelez SaveChanges, les règles de suppression en cascade s’appliqueront à toutes les entités qui sont suivies par le contexte.When you call SaveChanges, the cascade delete rules will be applied to any entities that are being tracked by the context. C’est le cas dans tous les exemples ci-dessus, c’est pourquoi le SQL généré pour supprimer l’entité principale/parent (le blog) et toutes les entités dépendantes/enfant (les billets) :This is the situation in all the examples shown above, which is why SQL was generated to delete both the principal/parent (blog) and all the dependents/children (posts):

    DELETE FROM [Posts] WHERE [PostId] = 1
    DELETE FROM [Posts] WHERE [PostId] = 2
    DELETE FROM [Blogs] WHERE [BlogId] = 1

Si seule l’entité principale est chargée, par exemple lorsqu’une requête est faite sur un blog sans Include(b => b.Posts) pour inclure également les billets, alors SaveChanges génère uniquement le SQL pour supprimer l’entité principale/parent :If only the principal is loaded--for example, when a query is made for a blog without an Include(b => b.Posts) to also include posts--then SaveChanges will only generate SQL to delete the principal/parent:

    DELETE FROM [Blogs] WHERE [BlogId] = 1

Les entités dépendantes/enfant (les billets) seront supprimées uniquement si la base de données a un comportement de cascade correspondant configuré.The dependents/children (posts) will only be deleted if the database has a corresponding cascade behavior configured. Si vous utilisez EF pour créer la base de données, ce comportement en cascade sera configuré pour vous.If you use EF to create the database, this cascade behavior will be setup for you.