c# - La nueva subentidad no se guardarĂ¡ cuando se guarde la entidad principal
entity-framework entity-framework-6.1 (1)
Trabajar con objetos desconectados necesita código adicional.
Si está trabajando con objetos desconectados, debe administrar la sincronización manualmente.
Si Bar
es una entidad existente, primero debes adjuntarla, por lo que Foo
se agregará como hijos Bar''s
.
if (foo.Bar.Id != 0)
{
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
}
El ejemplo del código anterior es similar con el ejemplo de Course
( Foo
) y Department
( Bar
) en este artículo .
Pero si Bar
es una entidad nueva, solo necesita agregar Foo
, entonces también se agregará Bar
.
else
{
context.Foos.Add(foo);
}
Se puede verificar alguna otra variedad en mi respuesta .
actualizar
Antes de seguir explicando, me gustaría mostrar un código idéntico.
-
db.Set<T>().Add(instance)
es igual adb.Entry(instance).State = EntityState.Added;
-
db.Set<T>().Attach(instance)
es igual adb.Entry(instance).State = EntityState.Unchanged;
La respuesta anterior explicaba dos condiciones.
Nueva Foo y Bar existente
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
Nuevo Foo y nuevo Bar
context.Foos.Add(foo);
Especial agregado
Added
tiene una condición especial, una vez que una entidad se marca como Added
. todas las entidades en el gráfico se marcarán como Added
también, incluso si cualquier entidad de referencia es un objeto existente en la base de datos. Si tenemos este código, se agregarán Foo y Bar.
var foo = new Foo (); // new foo
foo.Bar = new Bar { BarId = 123 }; // existing bar
db.Set<Foo>().Add(foo);
db.SaveChanges();
Para evitar que eso suceda, Bar debe estar conectado primero.
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();
Consulte el artículo de Julie Lerman para una explicación más completa.
La razón por la que sucede es que cuando utiliza el método DbSet.Add (es decir, Screencasts.Add), no solo el estado de la entidad raíz está marcado como "Agregado", sino que todo en el gráfico que el contexto no conocía previamente está marcado como Agregado también. Aunque el desarrollador puede estar al tanto de que el Tema tiene un valor Id existente, Entity Framework respeta su EntityState (Added) y crea un comando Insert database para el Tema, independientemente del Id existente.
Ajuste la explicación en función de su actualización
Y su pregunta actualizada es sobre Foo existente y el nuevo Bar. Usando su código, el resultado no agregará una nueva barra y Foo existente no establecerá una relación con la nueva barra.
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
Si agregamos manualmente la barra junto con AddOrUpdate(foo)
, el resultado sigue sin ser el esperado. Se agregará la nueva barra, pero Foo no tendrá relación con la nueva barra.
db.Bars.Add(foo.Bar);
db.Foos.AddOrUpdate(foo);
El comportamiento de AddOrUpdate
es inconsistente.
Solución
Si está trabajando con objetos desconectados, debe administrar la sincronización manualmente.
Este código debería funcionar en todas las condiciones.
- Nueva Foo y New Bar
- Nueva Foo y Bar existente
- Existente Foo y New Bar
- Existente Foo y Existing Bar
Este código depende de la identificación (id = 0 es una nueva entidad).
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();
En relación con AddOrUpdate
, creo que hay un problema abierto que se puede encontrar aquí .
Tengo una entidad matriz
foo
que existe en el DB, tengo una bar
propiedades en esta entidad (relación de uno a muchos).
Foo
está desapegado porque se deserializó usando WebApi, así que hago esto para foo
context.Foos.AddOrUpdate(foo);
Incluso si hay una nueva referencia de bar
adjunta, no se guardará, sin embargo, funciona así para otra relación que tenemos, que es una relación de muchos a muchos. Si agrego una nueva entidad a esa colección, se guardará en su tabla y también se agregará una fila a la tabla de relaciones.
Si hago context.Bars.AddOrUpdate(foo.Bar);
antes de llamar a context.Foos.AddOrUpdate(foo);
guardará la nueva barra correctamente en la barra, pero no agregará la barra correcta a la tabla foo
@Yuliam Chandra
Si entiendo tu respuesta correctamente (creo que estás mezclando barras y foos en tu respuesta), ¿debería funcionar?
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
Pero no lo hace