Lorsque j'enregistre une entité avec un cadre d'entité, j'ai naturellement supposé qu'il essaierait uniquement de sauvegarder l'entité spécifiée. Cependant, il essaie également de sauvegarder les entités enfants de cette entité. Cela pose toutes sortes de problèmes d'intégrité. Comment forcer EF à enregistrer uniquement l'entité que je souhaite enregistrer et donc à ignorer tous les objets enfants?
Si je définis manuellement les propriétés sur null, j'obtiens une erreur "L'opération a échoué: la relation n'a pas pu être modifiée car une ou plusieurs propriétés de clé étrangère ne peuvent pas être nulles." Ceci est extrêmement contre-productif car j'ai défini l'objet enfant sur null spécifiquement afin qu'EF le laisse seul.
Pourquoi est-ce que je ne veux pas enregistrer / insérer les objets enfants?
Étant donné que cela est discuté dans les deux sens dans les commentaires, je vais vous expliquer pourquoi je veux que mes objets enfants soient laissés seuls.
Dans l'application que je construis, le modèle d'objet EF n'est pas chargé à partir de la base de données, mais utilisé comme objets de données que je remplis lors de l'analyse d'un fichier plat. Dans le cas des objets enfants, beaucoup d'entre eux font référence à des tables de recherche définissant diverses propriétés de la table parent. Par exemple, l'emplacement géographique de l'entité principale.
Depuis que j'ai rempli ces objets moi-même, EF suppose qu'il s'agit de nouveaux objets et qu'ils doivent être insérés avec l'objet parent. Cependant, ces définitions existent déjà et je ne souhaite pas créer de doublons dans la base de données. J'utilise uniquement l'objet EF pour effectuer une recherche et remplir la clé étrangère dans mon entité de table principale.
Même avec les objets enfants qui sont des données réelles, je dois d'abord enregistrer le parent et obtenir une clé primaire ou EF semble juste faire un gâchis. J'espère que cela donne une explication.
la source
Réponses:
Autant que je sache, vous avez deux options.
Option 1)
Null tous les objets enfants, cela garantira à EF de ne rien ajouter. Il ne supprimera pas non plus quoi que ce soit de votre base de données.
Option 2)
Définissez les objets enfants comme détachés du contexte à l'aide du code suivant
Notez que vous ne pouvez pas détacher un
List
/Collection
. Vous devrez parcourir votre liste et détacher chaque élément de votre liste comme cecila source
Pour faire court: utilisez la clé étrangère et cela vous sauvera la journée.
Supposons que vous ayez une entité École et une entité Ville , et il s'agit d'une relation plusieurs-à-un où une Ville a plusieurs Écoles et une École appartient à une Ville. Et supposons que les villes existent déjà dans la table de recherche afin que vous ne vouliez PAS qu'elles soient à nouveau insérées lors de l'insertion d'une nouvelle école.
Au départ, vous pouvez définir vos entités comme ceci:
Et vous pouvez faire l' insertion de l' école comme ceci (supposons que vous avez déjà attribué la propriété City au newItem ):
L'approche ci-dessus peut parfaitement fonctionner dans ce cas, cependant, je préfère l' approche de clé étrangère qui pour moi est plus claire et flexible. Voir la solution mise à jour ci-dessous:
De cette manière, vous définissez explicitement que l' école a une clé étrangère City_Id et qu'elle fait référence à l' entité City . Donc quand il s'agit de l'insertion de l' école , vous pouvez faire:
Dans ce cas, vous spécifiez explicitement le City_Id du nouvel enregistrement et supprimez la ville du graphique afin qu'EF ne prenne pas la peine de l'ajouter au contexte avec School .
Bien qu'à la première impression, l'approche de la clé étrangère semble plus compliquée, mais croyez-moi, cette mentalité vous fera gagner beaucoup de temps lorsqu'il s'agira d'insérer une relation plusieurs-à-plusieurs (imaginer que vous avez une relation école-étudiant, et l'étudiant a une propriété City) et ainsi de suite.
J'espère que ça te sera utile.
la source
[Range(1, int.MaxValue)]
attribut?Si vous souhaitez simplement stocker les modifications apportées à un objet parent et éviter de stocker les modifications apportées à l'un de ses objets enfants , alors pourquoi ne pas procéder comme suit:
La première ligne attache l'objet parent et l'ensemble du graphique de ses objets enfants dépendants au contexte en
Unchanged
état.La deuxième ligne modifie l'état de l'objet parent uniquement, laissant ses enfants dans l'
Unchanged
état.Notez que j'utilise un contexte nouvellement créé, donc cela évite d'enregistrer d'autres modifications dans la base de données.
la source
L'une des solutions suggérées consiste à affecter la propriété de navigation à partir du même contexte de base de données. Dans cette solution, la propriété de navigation attribuée depuis l'extérieur du contexte de base de données serait remplacée. Veuillez consulter l'exemple suivant à titre d'illustration.
Enregistrement dans la base de données:
Microsoft enrôle cela comme une fonctionnalité, mais je trouve cela ennuyeux. Si l'objet de service associé à l'objet société a un ID qui existe déjà dans la base de données, pourquoi EF n'associe-t-il pas simplement l'objet société à l'objet de base de données? Pourquoi devrions-nous prendre soin de l'association par nous-mêmes? Prendre soin de la propriété de navigation lors de l'ajout d'un nouvel objet revient à déplacer les opérations de base de données de SQL vers C #, ce qui est fastidieux pour les développeurs.
la source
Vous devez d'abord savoir qu'il existe deux façons de mettre à jour l'entité dans EF.
Dans l'application que je construis, le modèle d'objet EF n'est pas chargé à partir de la base de données, mais utilisé comme objets de données que je remplis lors de l'analyse d'un fichier plat.
Cela signifie que vous travaillez avec un objet déconnecté, mais il n'est pas clair si vous utilisez une association indépendante ou une association de clé étrangère .
Ajouter
Lors de l'ajout d'une nouvelle entité avec un objet enfant existant (objet qui existe dans la base de données), si l'objet enfant n'est pas suivi par EF, l'objet enfant sera réinséré. Sauf si vous attachez d'abord manuellement l'objet enfant.
Mettre à jour
Vous pouvez simplement marquer l'entité comme modifiée, puis toutes les propriétés scalaires seront mises à jour et les propriétés de navigation seront simplement ignorées.
Graphique Diff
Si vous souhaitez simplifier le code lorsque vous travaillez avec un objet déconnecté, vous pouvez essayer de représenter graphiquement la bibliothèque de différences .
Voici l'introduction, Présentation de GraphDiff pour Entity Framework Code First - Permettre les mises à jour automatiques d'un graphique d'entités détachées .
Exemple de code
Insérez l'entité si elle n'existe pas, sinon mettez à jour.
Insérez l'entité si elle n'existe pas, sinon mettez à jour ET insérez l'objet enfant s'il n'existe pas, sinon mettez à jour.
la source
La meilleure façon de le faire est de remplacer la fonction SaveChanges dans votre datacontext.
la source
J'ai le même problème lorsque j'essaie de sauvegarder le profil, je table déjà des saluts et des nouveaux pour créer un profil. Lorsque j'insère un profil, il s'insère également dans la salutation. J'ai donc essayé comme ça avant savechanges ().
db.Entry (Profile.Salutation) .State = EntityState.Unchanged;
la source
Cela a fonctionné pour moi:
la source
Ce que nous avons fait, c'est avant d'ajouter le parent au dbset, déconnecter les collections enfants du parent, en veillant à pousser les collections existantes vers d'autres variables pour permettre de les utiliser plus tard, puis en remplaçant les collections enfants actuelles par de nouvelles collections vides. La définition des collections enfants sur null / rien a semblé échouer pour nous. Après cela, ajoutez le parent au dbset. De cette façon, les enfants ne sont pas ajoutés tant que vous ne le souhaitez pas.
la source
Je sais que c'est un ancien message, mais si vous utilisez l'approche du code d'abord, vous pouvez obtenir le résultat souhaité en utilisant le code suivant dans votre fichier de mappage.
Cela indiquera essentiellement à EF d'exclure la propriété "ChildObjectOrCollection" du modèle afin qu'elle ne soit pas mappée à la base de données.
la source
J'ai eu un défi similaire en utilisant Entity Framework Core 3.1.0, ma logique de dépôt est assez générique.
Cela a fonctionné pour moi:
Veuillez noter que "ParentEntityId" est le nom de la colonne de clé étrangère sur l'entité enfant. J'ai ajouté la ligne de code mentionnée ci-dessus sur cette méthode:
la source