La nouvelle sous-entité ne sera pas enregistrée lorsque l'entité parent est enregistrée
-
02-01-2020 - |
Question
J'ai une entité mère
foo
qui existe dans la base de données, j'ai une propriété bar
sur cette entité (Relation un à plusieurs).
Foo
est détaché car il est désérialisé à l'aide de WebApi, donc je fais cela pour foo
context.Foos.AddOrUpdate(foo);
Même s'il y a un nouveau bar
référence qui lui est attachée, elle ne sera pas enregistrée, mais elle fonctionne comme ceci pour une autre relation que nous avons qui est une relation Plusieurs à plusieurs.Si j'ajoute une nouvelle entité à cette collection, elle sera enregistrée dans sa table et une ligne est également ajoutée à la table des relations.
Si je fais context.Bars.AddOrUpdate(foo.Bar);
avant d'appeler context.Foos.AddOrUpdate(foo);
il enregistrera correctement la nouvelle barre dans la table bar, mais il n'ajoutera pas le bon barId à la table foo
@Yuliam Chandra
Si je comprends bien votre réponse (je pense que vous mélangez bars et foos dans votre réponse), cela devrait fonctionner ?
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
Mais ce n'est pas le cas
La solution
Travailler avec des objets déconnectés nécessite du code supplémentaire.
Si vous travaillez avec des objets déconnectés, vous devez gérer manuellement la synchronisation.
Si Bar
est une entité existante, vous devez d'abord l'attacher, donc Foo
sera ajouté comme Bar's
enfants.
if (foo.Bar.Id != 0)
{
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
}
L'exemple de code ci-dessus est similaire à Course
(Foo
) et Department
(Bar
) exemple dans Cet article.
Mais si Bar
est une nouvelle entité qu'il vous suffit d'ajouter Foo
, alors Bar
seront également ajoutés.
else
{
context.Foos.Add(foo);
}
Une autre variété peut être vérifiée ma réponse.
mise à jour
Avant d'expliquer davantage, j'aimerais afficher un code identique.
db.Set<T>().Add(instance)
est égal àdb.Entry(instance).State = EntityState.Added;
db.Set<T>().Attach(instance)
est égal àdb.Entry(instance).State = EntityState.Unchanged;
La réponse précédente expliquait deux conditions.
Nouveau Foo et Bar existant
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
Nouveau Foo et nouveau Bar
context.Foos.Add(foo);
Spécial ajouté
Added
a une condition spéciale, une fois qu'une entité est marquée comme Added
.toutes les entités du graphique seront marquées comme Added
également, même si une entité de référence est un objet existant dans la base de données.Si nous avons ce code, Foo et Bar seront ajoutés.
var foo = new Foo (); // new foo
foo.Bar = new Bar { BarId = 123 }; // existing bar
db.Set<Foo>().Add(foo);
db.SaveChanges();
Pour éviter que cela ne se produise, Bar doit d’abord être attaché.
var foo = new Foo (); // new foo
foo.Bar = new Bar { BarId = 123 }; // existing bar
db.Set<Bar>().Attach(bar);
db.Set<Foo>().Add(foo);
db.SaveChanges();
Vérifier Article de Julie Lerman pour une explication plus complète.
La raison pour laquelle cela se produit est que lorsque vous utilisez la méthode dbset.add (c'est-à-dire ScreencastS.Add), non seulement l'état de l'entité racine est marqué «ajouté», mais tout dans le graphique que le contexte n'était pas auparavant auparavant auparavant. est marqué également ajouté.Même si le développeur peut être conscient que le sujet a une valeur d'identification existante, l'entité Framework honore son entité (ajouté) et crée une commande de base de données d'insertion pour le sujet, quel que soit l'ID existant.
Ajustez l'explication en fonction de votre mise à jour
Et votre question mise à jour concerne les Foo existants et le nouveau Bar.En utilisant votre code, le résultat n'ajoutera pas de nouvelle Bar et les Foo existants n'établiront pas de relation avec la nouvelle Bar.
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
Si nous ajoutons manuellement la barre avec AddOrUpdate(foo)
, le résultat n'est toujours pas celui attendu.Le nouveau Bar sera ajouté, mais Foo n'aura aucune relation avec le nouveau Bar.
db.Bars.Add(foo.Bar);
db.Foos.AddOrUpdate(foo);
Le comportement de AddOrUpdate
est incohérent.
Solution
Si vous travaillez avec des objets déconnectés, vous devez gérer manuellement la synchronisation.
Ce code devrait fonctionner dans toutes les conditions.
- Nouveau Foo et Nouveau Bar
- Nouveau Foo et bar existant
- Foo existant et nouveau bar
- Foo existant et barre existante
Ce code dépend de l'identifiant (id = 0 est une nouvelle entité).
db.Entry(foo).State =
foo.FooId == 0 ? EntityState.Added : EntityState.Modified;
if (foo.Bar != null)
{
db.Entry(foo.Bar).State =
foo.Bar.BarId == 0 ? EntityState.Added : EntityState.Modified;
^^^
// If you don't want to change the Bar while creating a relationship between
// Foo and with existing Bar, you can change
// `EntityState.Modified` with `EntityState.Unchanged`
}
db.SaveChanges();
Relatif à AddOrUpdate
, je pense qu'il y a un problème ouvert qui peut être trouvé ici.