Kaskadierendes DeleteCascade Delete

Kaskadierendes Delete wird in der Datenbankterminologie häufig für die Beschreibung eines Merkmals verwendet, durch das beim Löschen einer Zeile automatisch das Löschen verknüpfter Zeilen ausgelöst wird.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. Ein eng damit verbundenes Löschverhalten, das ebenfalls von EF Core abgedeckt wird, besteht im automatischen Löschen einer untergeordneten Entität, wenn ihre Beziehung zu einer übergeordneten Entität getrennt wurde. Dies ist allgemein bekannt unter „Löschen verwaister Entitäten“.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 implementiert mehrere unterschiedliche Verhaltensweisen zum Löschen und ermöglicht die Konfiguration dieser Verhaltensweisen für einzelne Beziehungen.EF Core implements several different delete behaviors and allows for the configuration of the delete behaviors of individual relationships. Darüber hinaus implementiert EF Core Konventionen, mit denen basierend auf der Erforderlichkeit der Beziehung automatisch hilfreiches Standardlöschverhalten für die einzelnen Beziehungen konfiguriert wird.EF Core also implements conventions that automatically configure useful default delete behaviors for each relationship based on the requiredness of the relationship.

LöschverhaltenDelete behaviors

Das Löschverhalten wird im Enumeratortyp DeleteBehavior definiert und kann an die Fluent-API OnDelete übergeben werden, um zu steuern, ob das Löschen einer Prinzipalentität/übergeordneten Entität oder die Trennung der Beziehung zu abhängigen/untergeordneten Entitäten eine Nebenwirkung auf die abhängigen/untergeordneten Entitäten haben soll.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.

EF kann drei Aktionen ausführen, wenn eine Prinzipalentität/übergeordnete Entität gelöscht oder die Beziehung zur untergeordneten Entität gelöscht wird:There are three actions EF can take when a principal/parent entity is deleted or the relationship to the child is severed:

  • Die untergeordnete/abhängige Entität kann gelöscht werdenThe child/dependent can be deleted
  • Die Fremdschlüsselwerte der untergeordneten Entität können auf NULL festgelegt werdenThe child's foreign key values can be set to null
  • Die untergeordnete Entität bleibt unverändertThe child remains unchanged

Hinweis

Das im EF Core-Modell konfigurierte Löschverhalten wird nur angewendet, wenn die Prinzipalentität mit EF Core gelöscht wird und die abhängigen Entitäten in den Speicher geladen werden (d.h. für nachverfolgte abhängige Entitäten).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). In der Datenbank muss ein entsprechendes kaskadierendes Verhalten eingerichtet werden, um sicherzustellen, dass auf Daten, die nicht vom Kontext nachverfolgt werden, die erforderliche Aktion angewendet wird.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. Wenn Sie die Datenbank mit EF Core erstellen, wird dieses kaskadierende Verhalten für Sie eingerichtet.If you use EF Core to create the database, this cascade behavior will be setup for you.

Bei der zweiten, oben aufgeführten Aktion ist das Festlegen eines Fremdschlüsselwerts nicht gültig, wenn der Fremdschlüssel keine NULL-Werte zulässt.For the second action above, setting a foreign key value to null is not valid if foreign key is not nullable. (Ein Fremdschlüssel, der keine NULL-Werte zulässt, entspricht einer erforderlichen Beziehung.) In diesen Fällen verfolgt EF Core nach, ob die Fremdschlüsseleigenschaft bis zum Aufrufen von SaveChanges mit NULL markiert wurde. Zu diesem Zeitpunkt wird eine Ausnahme ausgelöst, da die Änderung in der Datenbank nicht beibehalten werden kann.(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. Dies ist vergleichbar mit dem Abrufen einer Einschränkungsverletzung aus der Datenbank.This is similar to getting a constraint violation from the database.

Es gibt vier Verhaltensweisen zum Löschen, die in der nachfolgenden Tabelle aufgeführt werden.There are four delete behaviors, as listed in the tables below.

Optionale BeziehungenOptional relationships

Bei optionalen Beziehungen (NULL-Werte zulassender Fremdschlüssel) kann ein NULL-Fremdschlüsselwert gespeichert werden. Dies hat folgende Auswirkungen:For optional relationships (nullable foreign key) it is possible to save a null foreign key value, which results in the following effects:

Name des VerhaltensBehavior Name Auswirkung auf abhängige/untergeordnete Entität im SpeicherEffect on dependent/child in memory Auswirkung auf abhängige/untergeordnete Entität in der DatenbankEffect on dependent/child in database
CascadeCascade Entitäten werden gelöschtEntities are deleted Entitäten werden gelöschtEntities are deleted
ClientSetNull (Standard)ClientSetNull (Default) Fremdschlüsseleigenschaften werden auf NULL festgelegtForeign key properties are set to null KeinerNone
SetNullSetNull Fremdschlüsseleigenschaften werden auf NULL festgelegtForeign key properties are set to null Fremdschlüsseleigenschaften werden auf NULL festgelegtForeign key properties are set to null
RestrictRestrict KeinerNone KeinerNone

Erforderliche BeziehungenRequired relationships

Bei erforderlichen Beziehungen (keine NULL-Werte zulassender Fremdschlüssel) kann kein NULL-Fremdschlüsselwert gespeichert werden. Dies hat folgende Auswirkungen:For required relationships (non-nullable foreign key) it is not possible to save a null foreign key value, which results in the following effects:

Name des VerhaltensBehavior Name Auswirkung auf abhängige/untergeordnete Entität im SpeicherEffect on dependent/child in memory Auswirkung auf abhängige/untergeordnete Entität in der DatenbankEffect on dependent/child in database
Cascade (Standard)Cascade (Default) Entitäten werden gelöschtEntities are deleted Entitäten werden gelöschtEntities are deleted
ClientSetNullClientSetNull Auslösung durch SaveChangesSaveChanges throws KeinerNone
SetNullSetNull Auslösung durch SaveChangesSaveChanges throws Auslösung durch SaveChangesSaveChanges throws
RestrictRestrict KeinerNone KeinerNone

In den obigen Tabellen kann Keiner zu einer Einschränkungsverletzung führen.In the tables above, None can result in a constraint violation. Wenn beispielsweise eine Prinzipalentität/untergeordnete Entität gelöscht wird, jedoch keine Maßnahmen zum Ändern des Fremdschlüssels einer abhängigen/untergeordneten Entität ergriffen werden, ist die Wahrscheinlichkeit groß, dass es in der Datenbank aufgrund einer Einschränkungsverletzung zu einer Auslösung durch SaveChanges kommt.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.

Allgemein:At a high level:

  • Verwenden Sie Cascade, wenn es Entitäten gibt, die ohne übergeordnete Entität nicht vorhanden sein können und EF die untergeordnete Entität automatisch löschen soll.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.
    • Entitäten, die ohne übergeordnete Entität nicht vorhanden sein können, verwenden in der Regel erforderliche Beziehungen. Hierfür gilt Cascade als Standard.Entities that cannot exist without a parent usually make use of required relationships, for which Cascade is the default.
  • Verwenden Sie ClientSetNull, wenn es Entitäten gibt, die möglicherweise über eine übergeordnete Entität verfügen und EF den Fremdschlüssel für Sie auf NULL festlegen sollIf 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
    • Entitäten, die ohne übergeordnete Entität vorhanden sein können, verwenden in der Regel optionale Beziehungen. Hierfür gilt ClientSetNull als Standard.Entities that can exist without a parent usually make use of optional relationships, for which ClientSetNull is the default.
    • Verwenden Sie SetNull, wenn in der Datenbank auch versucht werden soll, NULL-Werte an untergeordnete Fremdschlüssel zu verteilen, selbst wenn die untergeordnete Entität nicht geladen wurde.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. Beachten Sie jedoch, dass dieser Vorgang von der Datenbank unterstützt werden muss. Zudem kann eine derartige Konfiguration der Datenbank zu anderen Einschränkungen führen. Dadurch erweist sich diese Option in der Praxis häufig als unpraktisch.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. Aus diesem Grund ist SetNull nicht der Standard.This is why SetNull is not the default.
  • Verwenden Sie Restrict, wenn EF Core eine Entität niemals automatisch löschen oder den Fremdschlüssel automatisch auf NULL festlegen soll.If you don't want EF Core to ever delete an entity automatically or null out the foreign key automatically, then use Restrict. Beachten Sie, dass untergeordnete Entitäten und die zugehörigen Fremdschlüsselwerte hierfür in Ihrem Code manuell synchron gehalten werden müssen. Andernfalls werden Einschränkungsausnahmen ausgelöst.Note that this requires that your code keep child entities and their foreign key values in sync manually otherwise constraint exceptions will be thrown.

Hinweis

Anders als bei EF 6 treten kaskadierende Effekte in EF Core nicht automatisch auf, sondern nur, wenn SaveChanges aufgerufen wird.In EF Core, unlike EF6, cascading effects do not happen immediately, but instead only when SaveChanges is called.

Hinweis

Änderungen in EF Core 2.0: In vorherigen Releases hat Restrict dazu geführt, dass Eigenschaften optionaler Fremdschlüssel in nachverfolgten abhängigen Entitäten auf NULL festgelegt wurden. Dies war das Standardverhalten für optionale Beziehungen.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. In EF Core 2.0 wurde zur Darstellung dieses Verhaltens ClientSetNull eingeführt und als Standard für optionale Beziehungen festgelegt.In EF Core 2.0, the ClientSetNull was introduced to represent that behavior and became the default for optional relationships. Das Verhalten von Restrict wurde so angepasst, dass niemals Nebenwirkungen bei abhängigen Entitäten auftreten.The behavior of Restrict was adjusted to never have any side effects on dependent entities.

Beispiele für das Löschen von EntitätenEntity deletion examples

Der folgende Code ist Teil eines Beispiels, das heruntergeladen und ausgeführt werden kann.The code below is part of a sample that can be downloaded and run. Das Beispiel zeigt, was bei jedem Löschverhalten bei optionalen und erforderlichen Beziehungen geschieht, wenn eine übergeordnete Entität gelöscht wird.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)}");
}

Zum Verständnis werden die einzelnen Variationen im Folgenden ausführlich betrachtet.Let's walk through each variation to understand what is happening.

DeleteBehavior.Cascade mit erforderlicher oder optionaler BeziehungDeleteBehavior.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.
  • Blog ist als gelöscht markiertBlog is marked as Deleted
  • Beiträge bleiben anfangs unverändert, da es erst durch SaveChanges zu kaskadierendem Verhalten kommtPosts initially remain Unchanged since cascades do not happen until SaveChanges
  • SaveChanges sendet Löschvorgänge für abhängige/untergeordnete Entitäten (Beiträge) und anschließend für die Prinzipalentität/übergeordnete Entität (Blog)SaveChanges sends deletes for both dependents/children (posts) and then the principal/parent (blog)
  • Nach dem Speichern werden alle Entitäten getrennt, da sie jetzt aus der Datenbank gelöscht wurdenAfter saving, all entities are detached since they have now been deleted from the database

DeleteBehavior.ClientSetNull oder DeleteBehavior.SetNull mit erforderlicher BeziehungDeleteBehavior.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.
  • Blog ist als gelöscht markiertBlog is marked as Deleted
  • Beiträge bleiben anfangs unverändert, da es erst durch SaveChanges zu kaskadierendem Verhalten kommtPosts initially remain Unchanged since cascades do not happen until SaveChanges
  • SaveChanges versucht, den FS des Beitrags auf NULL festzulegen. Dieser Vorgang schlägt jedoch fehl, da der FS nicht auf NULL festgelegt werden kannSaveChanges attempts to set the post FK to null, but this fails because the FK is not nullable

DeleteBehavior.ClientSetNull oder DeleteBehavior.SetNull mit optionaler BeziehungDeleteBehavior.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.
  • Blog ist als gelöscht markiertBlog is marked as Deleted
  • Beiträge bleiben anfangs unverändert, da es erst durch SaveChanges zu kaskadierendem Verhalten kommtPosts initially remain Unchanged since cascades do not happen until SaveChanges
  • SaveChanges versucht, den FS von abhängigen/untergeordneten Entitäten (Beiträgen) vor dem Löschen der Prinzipalentität/übergeordneten Entität (Blog) auf NULL festzulegenSaveChanges attempts sets the FK of both dependents/children (posts) to null before deleting the principal/parent (blog)
  • Nach dem Speichern wird die Prinzipalentität/übergeordnete Entität (Blog) gelöscht, die abhängigen/untergeordneten Entitäten (Beiträge) werden jedoch weiter nachverfolgtAfter saving, the principal/parent (blog) is deleted, but the dependents/children (posts) are still tracked
  • Die nachverfolgten abhängigen/untergeordneten Entitäten (Beiträge) verfügen jetzt über NULL-FS-Werte und ihr Verweis auf die gelöschte Prinzipalentität/übergeordnete Entität (Blog) wurde entferntThe tracked dependents/children (posts) now have null FK values and their reference to the deleted principal/parent (blog) has been removed

DeleteBehavior.Restrict mit erforderlicher oder optionaler BeziehungDeleteBehavior.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.
  • Blog ist als gelöscht markiertBlog is marked as Deleted
  • Beiträge bleiben anfangs unverändert, da es erst durch SaveChanges zu kaskadierendem Verhalten kommtPosts initially remain Unchanged since cascades do not happen until SaveChanges
  • Da Restrict EF die Anweisung gibt, den FS nicht automatisch auf NULL festzulegen, bleibt der Wert ungleich NULL; es kommt zu einer Auslösung durch SaveChanges ohne SpeichernSince Restrict tells EF to not automatically set the FK to null, it remains non-null and SaveChanges throws without saving

Beispiele für das Löschen verwaister EntitätenDelete orphans examples

Der folgende Code ist Teil eines Beispiels, das heruntergeladen und ausgeführt werden kann.The code below is part of a sample that can be downloaded and run. Im Beispiel wird gezeigt, was bei jedem Löschverhalten bei optionalen und erforderlichen Beziehungen geschieht, wenn die Beziehung zwischen einer Prinzipalentität/übergeordneten Entität und den zugehörigen abhängigen/untergeordneten Entitäten getrennt wird.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. In diesem Beispiel wird die Beziehung durch Entfernen der abhängigen/untergeordneten Entitäten (Beiträge) aus der Navigationseigenschaft der Sammlung in der Prinzipalentität/übergeordneten Entität (Blog) getrennt.In this example, the relationship is severed by removing the dependents/children (posts) from the collection navigation property on the principal/parent (blog). Das Verhalten ist jedoch identisch, wenn der Verweis von abhängigen/untergeordneten Entitäten auf die Prinzipalentität/übergeordnete Entität stattdessen auf NULL festgelegt wird.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)}");
}

Zum Verständnis werden die einzelnen Variationen im Folgenden ausführlich betrachtet.Let's walk through each variation to understand what is happening.

DeleteBehavior.Cascade mit erforderlicher oder optionaler BeziehungDeleteBehavior.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.
  • Beiträge werden als „Geändert“ markiert, da der FS durch die Trennung der Beziehung als NULL markiert wurdePosts are marked as Modified because severing the relationship caused the FK to be marked as null
    • Wenn der FS nicht auf NULL festgelegt werden kann, wird der eigentliche Wert nicht geändert, auch wenn er als NULL markiert istIf the FK is not nullable, then the actual value will not change even though it is marked as null
  • SaveChanges sendet Löschvorgänge für abhängige/untergeordnete Entitäten (Beiträge)SaveChanges sends deletes for dependents/children (posts)
  • Nach dem Speichern werden die abhängigen/untergeordneten Entitäten (Beiträge) getrennt, da sie jetzt aus der Datenbank gelöscht wurdenAfter saving, the dependents/children (posts) are detached since they have now been deleted from the database

DeleteBehavior.ClientSetNull oder DeleteBehavior.SetNull mit erforderlicher BeziehungDeleteBehavior.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.
  • Beiträge werden als „Geändert“ markiert, da der FS durch die Trennung der Beziehung als NULL markiert wurdePosts are marked as Modified because severing the relationship caused the FK to be marked as null
    • Wenn der FS nicht auf NULL festgelegt werden kann, wird der eigentliche Wert nicht geändert, auch wenn er als NULL markiert istIf the FK is not nullable, then the actual value will not change even though it is marked as null
  • SaveChanges versucht, den FS des Beitrags auf NULL festzulegen. Dieser Vorgang schlägt jedoch fehl, da der FS nicht auf NULL festgelegt werden kannSaveChanges attempts to set the post FK to null, but this fails because the FK is not nullable

DeleteBehavior.ClientSetNull oder DeleteBehavior.SetNull mit optionaler BeziehungDeleteBehavior.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.
  • Beiträge werden als „Geändert“ markiert, da der FS durch die Trennung der Beziehung als NULL markiert wurdePosts are marked as Modified because severing the relationship caused the FK to be marked as null
    • Wenn der FS nicht auf NULL festgelegt werden kann, wird der eigentliche Wert nicht geändert, auch wenn er als NULL markiert istIf the FK is not nullable, then the actual value will not change even though it is marked as null
  • SaveChanges legt den FS von abhängigen/untergeordneten Entitäten auf NULL festSaveChanges sets the FK of both dependents/children (posts) to null
  • Nach dem Speichern verfügen die nachverfolgten abhängigen/untergeordneten Entitäten (Beiträge) jetzt über NULL-FS-Werte und ihr Verweis auf die gelöschte Prinzipalentität/übergeordnete Entität (Blog) wurde entferntAfter saving, the dependents/children (posts) now have null FK values and their reference to the deleted principal/parent (blog) has been removed

DeleteBehavior.Restrict mit erforderlicher oder optionaler BeziehungDeleteBehavior.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.
  • Beiträge werden als „Geändert“ markiert, da der FS durch die Trennung der Beziehung als NULL markiert wurdePosts are marked as Modified because severing the relationship caused the FK to be marked as null
    • Wenn der FS nicht auf NULL festgelegt werden kann, wird der eigentliche Wert nicht geändert, auch wenn er als NULL markiert istIf the FK is not nullable, then the actual value will not change even though it is marked as null
  • Da Restrict EF die Anweisung gibt, den FS nicht automatisch auf NULL festzulegen, bleibt der Wert ungleich NULL; es kommt zu einer Auslösung durch SaveChanges ohne SpeichernSince Restrict tells EF to not automatically set the FK to null, it remains non-null and SaveChanges throws without saving

Weitergabe an nicht verfolgte EntitätenCascading to untracked entities

Beim Aufruf von SaveChanges werden die Regeln des kaskadierenden Delete auf alle Entitäten angewendet, die vom Kontext nachverfolgt werden.When you call SaveChanges, the cascade delete rules will be applied to any entities that are being tracked by the context. Dies ist in allen oben aufgeführten Beispielen der Fall. Deshalb wurde SQL generiert, um die Prinzipalentität/übergeordnete Entität (Blog) und sämtliche abhängigen/untergeordneten Entitäten (Beiträge) zu löschen: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

Wenn nur die Prinzipalentität geladen wird – beispielsweise beim Ausführen einer Abfrage für einen Blog ohne Include(b => b.Posts) zum Einbeziehen von Beiträgen – generiert SaveChanges SQL nur zum Löschen der Prinzipalentität/übergeordneten Entität: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

Die abhängigen/untergeordneten Entitäten (Beiträge) werden nur gelöscht, wenn in der Datenbank ein entsprechendes kaskadierendes Verhalten konfiguriert wurde.The dependents/children (posts) will only be deleted if the database has a corresponding cascade behavior configured. Wenn Sie die Datenbank mit EF erstellen, wird dieses kaskadierende Verhalten für Sie eingerichtet.If you use EF to create the database, this cascade behavior will be setup for you.