La nueva subentidad no se guardará cuando se guarde la entidad principal
-
02-01-2020 - |
Pregunta
Tengo una entidad matriz
foo
que existe en la base de datos, tengo una propiedad bar
en esta entidad (relación uno a muchos).
Foo
está desconectado porque se deserializa usando WebApi, así que hago esto para foo
context.Foos.AddOrUpdate(foo);
Incluso si hay una nueva bar
referencia 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 lo hago context.Bars.AddOrUpdate(foo.Bar);
antes de llamar context.Foos.AddOrUpdate(foo);
guardará la nueva barra correctamente en la tabla de barras, pero no agregará el barId correcto a la tabla foo
@Yuliam Chandra
Si entiendo tu respuesta correctamente (creo que estás mezclando compases y foos en tu respuesta), ¿esto 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
Solución
Trabajar con objetos desconectados necesita código adicional.
Si está trabajando con objetos desconectados, debe administrar manualmente la sincronización.
Si Bar
es una entidad existente, primero debe adjuntarla, por lo que Foo
se agregará como Bar's
niños.
if (foo.Bar.Id != 0)
{
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
}
El ejemplo del código anterior es similar con Course
(Foo
) y Department
(Bar
) ejemplo en Este artículo.
Pero si Bar
es una nueva entidad que solo necesitas agregar Foo
, entonces Bar
También se agregará.
else
{
context.Foos.Add(foo);
}
Alguna otra variedad se puede consultar mi respuesta.
actualizar
Antes de seguir explicando, me gustaría mostrar un código idéntico.
db.Set<T>().Add(instance)
igual adb.Entry(instance).State = EntityState.Added;
db.Set<T>().Attach(instance)
igual adb.Entry(instance).State = EntityState.Unchanged;
La respuesta anterior explicaba dos condiciones.
Nuevo 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 está marcada 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 esto suceda, primero es necesario conectar Bar.
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();
Controlar Artículo de Julie Lerman para una explicación más completa.
La razón por la que sucede es que cuando usa el método dbset.add (es decir, screepenCasts.add), no solo el estado de la entidad raíz es marcado "agregado", sino todo en el gráfico que el contexto no estaba al tanto de está marcado también agregado.A pesar de que el desarrollador puede ser consciente de que el tema tiene un valor de identificación existente, Entity Framework honra a su EntityState (agregado) y crea un comando Insertar Database para el tema, independientemente de la ID existente.
Ajuste la explicación según su actualización
Y su pregunta actualizada es sobre Foo existente y la nueva Bar.Usando su código, el resultado no agregará una nueva barra y el 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 todavía no es el esperado.Se agregará la nueva Bar, pero Foo no tendrá relación con la nueva Bar.
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 manualmente la sincronización.
Este código debería funcionar en todas las condiciones.
- Nuevo Foo y Nuevo Bar
- Nuevo Foo y barra existente
- Foo existente y nueva barra
- Foo existente y barra existente
Este código depende de la identificación (id = 0 es una entidad nueva).
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();
Relacionado con AddOrUpdate
, Creo que hay un tema abierto que se puede encontrar. aquí.