Wenn ich eine Entität mit einem Entitätsframework speichere, gehe ich natürlich davon aus, dass nur versucht wird, die angegebene Entität zu speichern. Es wird jedoch auch versucht, die untergeordneten Entitäten dieser Entität zu speichern. Dies verursacht alle möglichen Integritätsprobleme. Wie zwinge ich EF, nur die Entität zu speichern, die ich speichern möchte, und ignoriere daher alle untergeordneten Objekte?
Wenn ich die Eigenschaften manuell auf null setze, wird die Fehlermeldung "Der Vorgang ist fehlgeschlagen: Die Beziehung konnte nicht geändert werden, da eine oder mehrere der Fremdschlüsseleigenschaften nicht nullwertfähig sind." Dies ist äußerst kontraproduktiv, da ich das untergeordnete Objekt speziell auf null gesetzt habe, damit EF es in Ruhe lässt.
Warum möchte ich die untergeordneten Objekte nicht speichern / einfügen?
Da dies in den Kommentaren hin und her diskutiert wird, werde ich begründen, warum ich möchte, dass meine untergeordneten Objekte in Ruhe gelassen werden.
In der Anwendung, die ich erstelle, wird das EF-Objektmodell nicht aus der Datenbank geladen, sondern als Datenobjekt verwendet, das ich beim Parsen einer Einfachdatei auffülle. Bei den untergeordneten Objekten beziehen sich viele davon auf Nachschlagetabellen, die verschiedene Eigenschaften der übergeordneten Tabelle definieren. Zum Beispiel der geografische Standort der primären Entität.
Da ich diese Objekte selbst ausgefüllt habe, geht EF davon aus, dass es sich um neue Objekte handelt, die zusammen mit dem übergeordneten Objekt eingefügt werden müssen. Diese Definitionen sind jedoch bereits vorhanden und ich möchte keine Duplikate in der Datenbank erstellen. Ich verwende das EF-Objekt nur zum Nachschlagen und Auffüllen des Fremdschlüssels in meiner Haupttabellenentität.
Selbst bei den untergeordneten Objekten, bei denen es sich um echte Daten handelt, muss ich zuerst das übergeordnete Objekt speichern und einen Primärschlüssel erhalten, oder EF scheint nur ein Durcheinander zu verursachen. Hoffe das gibt eine Erklärung.
quelle
Antworten:
Soweit ich weiß, haben Sie zwei Möglichkeiten.
Option 1)
Setzen Sie alle untergeordneten Objekte auf Null, um sicherzustellen, dass EF nichts hinzufügt. Es wird auch nichts aus Ihrer Datenbank gelöscht.
Option 2)
Stellen Sie die untergeordneten Objekte mithilfe des folgenden Codes als vom Kontext getrennt ein
Beachten Sie, dass Sie ein
List
/ nicht trennen könnenCollection
. Sie müssen Ihre Liste durchlaufen und jedes Element in Ihrer Liste wie folgt trennenquelle
Lange Rede, kurzer Sinn: Verwenden Sie den Fremdschlüssel, um Ihren Tag zu retten.
Angenommen , Sie haben Schule Einheit und eine Stadt Einheit, und dies ist ein Viele-zu-eins - Beziehung , wo eine Stadt viele Schulen und eine Schule gehören in einer Stadt hat. Angenommen, die Städte sind bereits in der Nachschlagetabelle vorhanden, sodass Sie NICHT möchten, dass sie beim Einfügen einer neuen Schule erneut eingefügt werden.
Zunächst können Sie Ihre Entitäten wie folgt definieren:
Und Sie könnten das tun Schule Einsetzen wie folgt aus (vorausgesetzt , dass Sie bereits über Stadt - Eigenschaft auf dem zugewiesenen newItem ):
Der obige Ansatz mag in diesem Fall perfekt funktionieren, ich bevorzuge jedoch den Fremdschlüsselansatz , der für mich klarer und flexibler ist. Siehe die aktualisierte Lösung unten:
Auf diese Weise definieren Sie explizit, dass die Schule einen Fremdschlüssel City_Id hat und sich auf die Entität City bezieht . Wenn es also um das Einfügen von Schule geht , können Sie Folgendes tun:
In diesem Fall geben Sie die City_Id des neuen Datensatzes explizit an und entfernen die City aus dem Diagramm, damit EF sie nicht zusammen mit School zum Kontext hinzufügt .
Auf den ersten Blick scheint der Fremdschlüsselansatz komplizierter zu sein, aber glauben Sie mir, diese Mentalität spart Ihnen viel Zeit, wenn Sie eine Viele-zu-Viele-Beziehung einfügen (im Bild haben Sie eine Schul- und Schülerbeziehung und den Schüler hat ein Stadteigentum) und so weiter.
Hoffe das ist hilfreich für dich.
quelle
[Range(1, int.MaxValue)]
Attribut anzugeben ?Wenn Sie nur Änderungen an einem übergeordneten Objekt speichern und das Speichern von Änderungen an einem der untergeordneten Objekte vermeiden möchten, gehen Sie wie folgt vor:
In der ersten Zeile werden das übergeordnete Objekt und das gesamte Diagramm der abhängigen untergeordneten Objekte an den Kontext im
Unchanged
Status angehängt.In der zweiten Zeile wird der Status nur für das übergeordnete Objekt geändert, sodass die untergeordneten Objekte im
Unchanged
Status verbleiben .Beachten Sie, dass ich einen neu erstellten Kontext verwende, damit keine anderen Änderungen an der Datenbank gespeichert werden.
quelle
Eine der vorgeschlagenen Lösungen besteht darin, die Navigationseigenschaft aus demselben Datenbankkontext zuzuweisen. In dieser Lösung wird die von außerhalb des Datenbankkontexts zugewiesene Navigationseigenschaft ersetzt. Zur Veranschaulichung siehe folgendes Beispiel.
In Datenbank speichern:
Microsoft schreibt dies als Feature ein, aber ich finde das ärgerlich. Wenn das dem Firmenobjekt zugeordnete Abteilungsobjekt eine ID hat, die bereits in der Datenbank vorhanden ist, warum ordnet EF dann nicht einfach das Firmenobjekt dem Datenbankobjekt zu? Warum sollten wir uns selbst um den Verein kümmern müssen? Die Pflege der Navigationseigenschaft beim Hinzufügen eines neuen Objekts ist so etwas wie das Verschieben der Datenbankoperationen von SQL nach C #, was für die Entwickler umständlich ist.
quelle
Zunächst müssen Sie wissen, dass es zwei Möglichkeiten gibt, die Entität in EF zu aktualisieren.
In der Anwendung, die ich erstelle, wird das EF-Objektmodell nicht aus der Datenbank geladen, sondern als Datenobjekt verwendet, das ich beim Parsen einer Einfachdatei auffülle.
Das bedeutet, dass Sie mit nicht verbundenen Objekten arbeiten, aber es ist unklar, ob Sie eine unabhängige Zuordnung oder eine Fremdschlüsselzuordnung verwenden .
Hinzufügen
Wenn beim Hinzufügen einer neuen Entität mit einem vorhandenen untergeordneten Objekt (Objekt, das in der Datenbank vorhanden ist) das untergeordnete Objekt nicht von EF verfolgt wird, wird das untergeordnete Objekt erneut eingefügt. Es sei denn, Sie hängen das untergeordnete Objekt zuerst manuell an.
Aktualisieren
Sie können die Entität einfach als geändert markieren, dann werden alle Skalareigenschaften aktualisiert und die Navigationseigenschaften werden einfach ignoriert.
Graph Diff
Wenn Sie den Code bei der Arbeit mit nicht verbundenen Objekten vereinfachen möchten, können Sie versuchen, die Diff-Bibliothek grafisch darzustellen .
Hier ist die Einführung: Einführung in GraphDiff für Entity Framework-Code zuerst - Ermöglichen automatisierter Aktualisierungen eines Diagramms von getrennten Entitäten .
Beispielcode
Entität einfügen, falls nicht vorhanden, andernfalls aktualisieren.
Entität einfügen , wenn sie nicht vorhanden ist, andernfalls aktualisieren UND untergeordnetes Objekt einfügen, falls nicht vorhanden, andernfalls aktualisieren.
quelle
Der beste Weg, dies zu tun, besteht darin, die SaveChanges-Funktion in Ihrem Datenkontext zu überschreiben.
quelle
Ich habe das gleiche Problem, wenn ich versuche, ein Profil zu speichern. Ich habe bereits eine Tabellenanrede und ein neues Profil erstellt. Wenn ich ein Profil einfüge, wird es auch in die Anrede eingefügt. Also habe ich es vor savechanges () so versucht.
db.Entry (Profile.Salutation) .State = EntityState.Unchanged;
quelle
Das hat bei mir funktioniert:
quelle
Wir haben vor dem Hinzufügen des übergeordneten Elements zum dbset die untergeordneten Sammlungen vom übergeordneten getrennt, die vorhandenen Sammlungen auf andere Variablen verschoben, um später mit ihnen arbeiten zu können, und anschließend die aktuellen untergeordneten Sammlungen durch neue leere Sammlungen ersetzt. Das Setzen der untergeordneten Sammlungen auf null / nichts schien für uns fehlzuschlagen. Fügen Sie anschließend das übergeordnete Element zum DBSet hinzu. Auf diese Weise werden die Kinder erst hinzugefügt, wenn Sie dies wünschen.
quelle
Ich weiß, dass es ein alter Beitrag ist. Wenn Sie jedoch den Code-First-Ansatz verwenden, können Sie das gewünschte Ergebnis erzielen, indem Sie den folgenden Code in Ihrer Zuordnungsdatei verwenden.
Dadurch wird EF grundsätzlich angewiesen, die Eigenschaft "ChildObjectOrCollection" vom Modell auszuschließen, damit sie nicht der Datenbank zugeordnet wird.
quelle
Ich hatte eine ähnliche Herausforderung mit Entity Framework Core 3.1.0, meine Repo-Logik ist ziemlich allgemein.
Das hat bei mir funktioniert:
Bitte beachten Sie, dass "ParentEntityId" der Name der Fremdschlüsselspalte in der untergeordneten Entität ist. Ich habe die oben genannte Codezeile zu dieser Methode hinzugefügt:
quelle