Новый вложенный объект не будет сохранен при сохранении родительского объекта

StackOverflow https://stackoverflow.com//questions/25078798

Вопрос

У меня есть родительская сущность

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, я думаю , что есть открытый вопрос , который можно найти здесь.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top