Elter mit Kindern in einer Beziehung löschen

8

Ich habe eine .NET4.0-Anwendung mit Entity Framework 5.0 und Sql Server CE 4.0.

Ich habe zwei Entitäten mit einer Eins-zu-Vielen-Beziehung (Eltern / Kind). Ich habe es so konfiguriert, dass es bei der Elterentfernung kaskadiert wird, aber aus irgendeinem Grund scheint es nicht zu funktionieren.

Hier ist eine vereinfachte Version meiner Entitäten:

%Vor%

Die Verbindungszeichenfolge:

%Vor%

Und eine vereinfachte Version des Workflows meiner App:

%Vor%

Wenn ich versuche, die übergeordnete Entität zu löschen, wird Folgendes ausgelöst:

  

Die Beziehung konnte nicht geändert werden, weil einer oder mehrere der   Fremdschlüsseleigenschaften sind nicht nullfähig. Wenn eine Änderung an a vorgenommen wird   Beziehung, die zugehörige Fremdschlüsseleigenschaft wird auf einen Nullwert festgelegt.   Wenn der Fremdschlüssel keine Nullwerte unterstützt, eine neue Beziehung   muss definiert sein, die Fremdschlüsseleigenschaft muss eine andere zugewiesen werden   Nicht-Null-Wert oder das nicht verwandte Objekt muss gelöscht werden.

Ich glaube, meine Beziehungskonfiguration ist in Ordnung ( folgte der Dokumentation ). Ich suchte auch nach Richtlinien zum Löschen gelöster Objekte .

Ich kann wirklich nicht verstehen, warum das Löschen nicht funktioniert. Ich möchte vermeiden, alle Kinder zu laden, sie einzeln zu löschen und sie das Elternteil zu löschen, weil es eine bessere Lösung als das geben muss.

    
Arthur Nunes 15.05.2013, 12:32
quelle

2 Antworten

12

Das Festlegen des Status einer Entität auf Deleted und das Aufrufen von DbSet<T>.Remove für diese Entität sind nicht identisch.

Der Unterschied besteht darin, dass das Setzen des Status nur den Status der Root-Entität (die in context.Entry übergeben wird) in Deleted ändert, aber nicht den Status verwandter Entitäten, während Remove dies tut, wenn die Beziehung konfiguriert ist mit kaskadierendem Löschen.

Wenn Sie eine Ausnahme erhalten, hängt es tatsächlich davon ab, ob die Kinder (alle oder nur ein Teil) an den Kontext gebunden sind oder nicht. Dies führt zu einem Verhalten, das etwas schwierig zu folgen ist:

  • Wenn Sie Remove aufrufen, erhalten Sie keine Ausnahme, egal ob Kinder geladen sind oder nicht. Es gibt noch einen Unterschied:
    • Wenn die untergeordneten Elemente mit dem Kontext verknüpft sind, generiert EF eine DELETE -Anweisung für jedes angefügte Kind und dann für das übergeordnete Element (weil Remove alle als Deleted markiert hat)
    • Wenn die untergeordneten Elemente nicht mit dem Kontext verknüpft sind, sendet EF nur eine DELETE -Anweisung für das übergeordnete Element an die Datenbank, und da die kaskadierende Löschung aktiviert ist, löscht die Datenbank auch die untergeordneten Elemente.
  • Wenn Sie den Status der Root-Entität auf Deleted setzen, können Sie möglicherweise eine Ausnahme erhalten:
    • Wenn untergeordnete Elemente an den Kontext gebunden sind, wird ihr Status nicht auf Deleted festgelegt, und EF beschwört, dass Sie versuchen, einen Prinzipal (die Stammentität) in einer erforderlichen Beziehung zu löschen, ohne die abhängigen Elemente (die untergeordneten Elemente) zu löschen. oder zumindest ohne ihre Fremdschlüssel auf eine andere Root-Entität zu setzen, die nicht in Deleted state ist. Das ist die Ausnahme, die Sie hatten: account ist der Stamm und user1 ist abhängig von account und der Aufruf von context.Entry(account).State = EntityState.Deleted; fügt auch user1 im Status Unchanged an den Kontext an (oder ändert die Erkennung in SaveChanges werde es tun, da bin ich mir nicht sicher. user1 ist Teil der account.Users -Sammlung, weil das Relation Fixup es der Sammlung im ersten Kontext hinzugefügt hat, obwohl Sie es nicht explizit in Ihrem Code hinzugefügt haben.
    • Wenn keine Kinder an den Kontext gebunden sind, wird der Status des Stamms an Deleted eine DELETE -Anweisung an die Datenbank senden, und erneutes kaskadierendes Löschen in der Datenbank wird auch die Kinder löschen. Dies funktioniert ohne Ausnahme. Ihr Code würde dann zum Beispiel funktionieren, wenn Sie account.Users = null vor dem Setzen des Status auf Deleted im zweiten Kontext oder vor dem Eintritt in den zweiten Kontext setzen.

Meiner Meinung nach mit Remove ...

%Vor%

... ist eindeutig der bevorzugte Weg, da das Verhalten von Remove viel mehr dem entspricht, was Sie für eine erforderliche Beziehung mit kaskadierendem Löschen erwarten würden (was in Ihrem Modell der Fall ist). Die Abhängigkeit des Verhaltens einer manuellen Statusänderung von Zuständen anderer Entitäten macht die Verwendung schwieriger. Ich würde es als fortgeschrittene Verwendung nur für spezielle Fälle betrachten.

Der Unterschied ist nicht allgemein bekannt oder dokumentiert. Ich habe sehr wenige Beiträge darüber gesehen. Das einzige, das ich jetzt wieder finden konnte, ist dieses von Zeeshan Hirani .

    
Slauma 15.05.2013, 23:47
quelle
1

Ich habe einen etwas anderen Ansatz versucht und seltsamerweise hat es funktioniert. Wenn ich diesen Code ersetze:

%Vor%

Durch diesen:

%Vor%

Es funktioniert ohne weitere Probleme. Ich bin mir nicht sicher, ob das ein Fehler ist oder ob mir etwas fehlt. Ich würde wirklich etwas Licht über die Angelegenheit schätzen, weil ich ziemlich sicher war, dass der erste Weg (EntityState.Deleted) der empfohlene war.

    
Arthur Nunes 15.05.2013 12:32
quelle