Новый вложенный объект не будет сохранен при сохранении родительского объекта
-
02-01-2020 - |
Вопрос
У меня есть родительская сущность
foo
который существует в базе данных, у меня есть свойство bar
об этой сущности (отношение "Один ко многим").
Foo
отсоединяется, потому что его десериализуют с помощью WebAPI, поэтому я делаю это, чтобы foo
context.Foos.AddOrUpdate(foo);
Даже если появится новый bar
ссылка, прикрепленная к нему, не будет сохранена, однако она работает подобным образом для другого отношения, которое у нас есть, которое является отношением "Многие ко многим".Если я добавлю новый объект в эту коллекцию, он будет сохранен в ее таблице, а также строка будет добавлена в таблицу отношений.
Если я это сделаю context.Bars.AddOrUpdate(foo.Bar);
перед звонком context.Foos.AddOrUpdate(foo);
это правильно сохранит новую строку в таблице bar, но не добавит правильный barId в таблицу foo
@Юлиам Чандра
Если я правильно понял ваш ответ (я думаю, вы путаете бары и foo в своем ответе), это должно сработать?
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
Но это не так
Решение
Для работы с отключенными объектами требуется дополнительный код.
Если вы работаете с отключенными объектами, вы должны вручную управлять синхронизацией.
Если Bar
это существующий объект, к которому вам нужно сначала присоединить его, так что Foo
будет добавлено как Bar's
дети.
if (foo.Bar.Id != 0)
{
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
}
Приведенный выше пример кода аналогичен Course
(Foo
) и Department
(Bar
) пример в эта статья.
Но если Bar
это новая сущность, которую вам просто нужно добавить Foo
, тогда Bar
также будут добавлены.
else
{
context.Foos.Add(foo);
}
Какой-нибудь другой сорт можно проверить на мой ответ.
Обновить
Прежде чем объяснять дальше, я хотел бы показать идентичный код.
db.Set<T>().Add(instance)
равноdb.Entry(instance).State = EntityState.Added;
db.Set<T>().Attach(instance)
равноdb.Entry(instance).State = EntityState.Unchanged;
В предыдущем ответе объяснялось о двух условиях.
Новый Foo и существующий Bar
context.Bars.Attach(foo.Bar);
context.Foos.AddOrUpdate(foo);
Новый Foo и новый Bar
context.Foos.Add(foo);
Добавлено Специальное Предложение
Added
имеет особое условие, как только объект помечен как Added
.все объекты на графике будут помечены как Added
тоже, даже если какой-либо ссылочный объект является существующим объектом в базе данных.Если у нас есть этот код, будут добавлены Foo и Bar.
var foo = new Foo (); // new foo
foo.Bar = new Bar { BarId = 123 }; // existing bar
db.Set<Foo>().Add(foo);
db.SaveChanges();
Чтобы этого не произошло, сначала необходимо прикрепить планку.
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();
Проверить Статья Джули Лерман для более полного объяснения.
Причина, по которой это происходит, заключается в том, что при использовании метода DbSet.Add (то есть Screencasts.Add) отмечается не только состояние корневого объекта “Добавлено”, но все на графике, о чем контекст не знал ранее, также помечено как Добавленное.Даже если разработчик может знать, что Тема имеет существующее значение Id, Entity Framework учитывает ее EntityState (добавлено) и создает команду Insert database для темы, независимо от существующего Id.
Скорректируйте Объяснение В зависимости от Вашего обновления
И ваш обновленный вопрос касается существующих Foo и new Bar.Используя ваш код, результат не добавит новую строку, а существующий Foo не установит связь с new Bar.
var foo = new Foo();
foo.FooId = 524 //Existing foo;
foo.Bar = new Bar(); //Completely new bar
db.Foos.AddOrUpdate(foo);
db.SaveChanges();
Если мы вручную добавим Панель вместе с AddOrUpdate(foo)
, результат по-прежнему не такой, как ожидалось.Новая панель будет добавлена, но Foo не будет иметь отношения к новой панели.
db.Bars.Add(foo.Bar);
db.Foos.AddOrUpdate(foo);
Поведение AddOrUpdate
является непоследовательным.
Решение
Если вы работаете с отключенными объектами, вы должны вручную управлять синхронизацией.
Этот код должен работать в любых условиях.
- Новый Foo и Новый Bar
- Новый Foo и Существующий Bar
- Существующий Foo и Новый Bar
- Существующий Foo и Существующий Bar
Этот код зависит от идентификатора (id = 0 - это новая сущность).
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();
Связанный с AddOrUpdate
, я думаю , что есть открытый вопрос , который можно найти здесь.