EntityFramework CodeFirst: CASCADE DELETE für eine Viele-zu-Viele-Beziehung einer Tabelle

8

Ich habe ein Eintrags-Entfernungsproblem mit dem EntityFramework und eine Viele-zu-Viele-Beziehung für dieselbe Entität. Betrachten Sie dieses einfache Beispiel:

Entität:

%Vor%

Fließende API-Konfiguration:

%Vor%
  1. Stimmt es, dass es nicht möglich ist, die Cascade Delete in der Fluent API zu definieren?
  2. Wie löscht man am besten UserEntity , zum Beispiel Foo ?

    Er sucht jetzt nach mir, ich muss Clear die Foo s Friends Sammlung, dann muss ich alle anderen UserEntities laden, die Foo in Friends enthalten, und dann entfernen Foo aus jeder Liste, bevor ich Foo von Users entferne. Aber es klingt zu kompliziert.

  3. Ist es möglich direkt auf die relationale Tabelle zuzugreifen, damit ich solche Einträge entfernen kann

    %Vor%

Danke!

Update01:

  1. Meine beste Lösung für dieses Problem besteht darin, die rohe SQL-Anweisung auszuführen, bevor ich SaveChanges :

    aufruft %Vor%

    Aber der Nachteil davon ist, dass, wenn SaveChanges aus irgendeinem Grund fehlschlägt, die FriendshipRelation bereits entfernt sind und nicht zurückgerollt werden konnten. Oder irre ich mich?

tenbits 18.09.2015, 15:38
quelle

2 Antworten

9

Problem 1

Die Antwort ist ganz einfach:

Entity Framework kann Kaskadenlöschung nicht definieren, wenn es nicht weiß, welche Eigenschaften zu der Beziehung gehören.

Zusätzlich gibt es in einer Viele: Viele Beziehung eine dritte Tabelle, die für die Verwaltung der Beziehung zuständig ist. Diese Tabelle muss mindestens 2 FKs haben. Sie sollten die Kaskadenlöschung für jede FK konfigurieren, nicht für die "gesamte Tabelle".

Die Lösung besteht darin, die Entität FriendshipRelation zu erstellen. So:

%Vor%

Nun musst du UserEntity ändern. Anstelle einer Sammlung von UserEntity hat es eine Sammlung von UserFriendship . So:

%Vor%

Sehen wir uns das Mapping an:

%Vor%

Generierte Migration:

%Vor%

Um alle Freunde des Benutzers abzurufen:

%Vor%

All das funktioniert gut. Es gibt jedoch ein Problem bei der Zuordnung (was auch in Ihrem aktuellen Mapping passiert). Angenommen, "I" ist ein UserEntity :

  • Ich habe eine Freundschaftsanfrage an John gestellt - John hat
  • akzeptiert
  • Ich habe eine Freundschaftsanfrage an Ann - Ann gemacht
  • Richard hat mir eine Freundschaftsanfrage gestellt - ich habe
  • akzeptiert

Wenn ich meine Eigenschaft Friends abrufe, wird "John", "Ann", aber nicht "Richard" zurückgegeben. Warum? weil Richard der "Maker" der Beziehung ist, nicht ich. Die Eigenschaft Friends ist nur an eine Seite der Beziehung gebunden.

Ok. Wie kann ich das lösen? Einfach! Ändere deine UserEntity -Klasse:

%Vor%

Aktualisieren Sie das Mapping:

%Vor%

Es sind keine Migrationen notwendig.

Um alle Freunde des Benutzers abzurufen:

%Vor%

Problem 2

Ja, Sie müssen die Sammlung iterieren und alle untergeordneten Objekte entfernen. Sehen Sie meine Antwort in diesem Thread Saubere Aktualisierung einer Hierarchie in Entity Framework

Nach meiner Antwort erstellen Sie einfach ein UserFriendship dbset:

%Vor%

Jetzt können Sie alle Freunde einer bestimmten Benutzer-ID abrufen, löschen Sie alle auf einmal und entfernen Sie den Benutzer.

Problem 3

Ja, das ist möglich. Sie haben jetzt ein UserFriendship dbset.

Ich hoffe, es hilft!

    
Fabio Luz 25.09.2015, 03:35
quelle
1

1) Ich sehe keinen direkten Weg, um die Kaskade der Viele-zu-Viele-Beziehungen mit FluentApi zu kontrollieren.

2) Die einzige verfügbare Möglichkeit, die ich kontrollieren kann, ist die Verwendung von ManyToManyCascadeDeleteConvention , was meiner Meinung nach standardmäßig aktiviert ist, zumindest für mich. Ich habe gerade eine meiner Migrationen überprüft, einschließlich einer Viele-zu-Viele-Beziehung, und tatsächlich ist die cascadeDelete: true für beide Schlüssel vorhanden.

BEARBEITEN: Entschuldigung, ich habe gerade festgestellt, dass die ManyToManyCascadeDeleteConvention den Fall der Selbstreferenzierung nicht abdeckt. Diese verwandte Frage lautet, dass

  

Sie erhalten diese Fehlermeldung, da eine Tabelle in SQL Server nicht mehr als einmal in einer Liste aller kaskadierenden referenziellen Aktionen angezeigt werden kann, die entweder durch eine DELETE- oder eine UPDATE-Anweisung gestartet werden. Beispielsweise muss der Baum der kaskadierenden referenziellen Aktionen nur einen Pfad zu einer bestimmten Tabelle in der kaskadierenden referenziellen Aktionsstruktur haben.

Sie müssen also einen benutzerdefinierten Löschcode haben (wie den sql-Befehl, den Sie bereits haben) und ihn in einem Transaktionsumfang .

3) Sie sollten nicht aus dem Kontext auf diese Tabelle zugreifen können. Normalerweise ist die durch eine Viele-zu-Viele-Beziehung erzeugte Tabelle ein Nebenprodukt der Implementierung in einem relationalen DBMS und wird als eine schwache Tabelle entsprechend der zugehörigen Tabellen betrachtet, was bedeutet, dass ihre Zeilen sein sollten kaskadengelöscht, wenn eine der zugehörigen Entitäten entfernt wird.

Ich rate Ihnen zunächst, zu überprüfen, ob Ihre Migration die Fremdschlüssel für Tabellen auf das Löschen in Kaskade setzt. Wenn Sie dann aus irgendeinem Grund die Löschung eines Datensatzes mit zugehörigen Datensätzen in der Viele-zu-Viele-Beziehung einschränken müssen, dann suchen Sie in Ihren Transaktionen einfach danach.

4) Wenn Sie das wirklich möchten (FluentApi aktiviert standardmäßig ManyToManyCascadeDeleteConvention ), müssen Sie den Befehl sql und Ihre SaveChanges in einen Transaktionsbereich einschließen.

    
Green Magic 24.09.2015 15:35
quelle