Внешние ключи к другим существующим сущностям не сохраняются при обновлении ссылочной сущности - PullRequest
1 голос
/ 11 ноября 2011

У меня есть объект POCO A, ссылающийся на объект B, скажем, b. Я хочу, чтобы A ссылался на другую существующую B сущность, скажем, bb.

Эти шаги:

var b = // get existing b from somewhere out-of-context
var a = new A { B = b }
dbcontext.Set<B>.Attach(a.B);
dbcontext.Set<A>.Add(a);
context.SaveChanges();

генерирует оператор вставки для a, как и ожидалось, с внешним ключом B_ID, для которого правильно установлен идентификатор первичного ключа b. Эти последующие шаги:

var bb = // get existing bb from somewhere out-of-context
a.B = bb;
differentdbcontext.Set<B>.Attach(a.B);
differentdbcontext.Set<A>.Attach(a);
differentdbcontext.Entry(a).State = EntityState.Modified;
differentdbcontext.SaveChanges();

не приводит к изменению сохраняемых данных. Оператор обновления не включает set B_ID = ..., как ожидалось.

Я делаю что-то не так, потому что раньше у меня были другие сценарии, подобные этому.

1 Ответ

1 голос
/ 12 ноября 2011

Установка состояния на Modified влияет только на скалярные свойства, но не на ваши свойства навигации. Я предполагаю, что B_ID не является свойством в вашей модели, а только столбец внешнего ключа в базе данных, который не доступен вашей модели.

В этом случае вы можете обновить взаимосвязь, только используя автоматическое обнаружение изменений Entity Framework. Один из подходов - и я бы назвал это стандартным подходом - это загрузить оригинальную A , включая оригинальную B, из базы данных, установить a.B в новую bb и затем сохранить изменения:

var bb = // get existing bb from somewhere out-of-context

differentdbcontext.Set<B>().Attach(bb);
differentdbcontext.Set<A>().Include(x => x.B).Single(x => x.Id == a.Id);

a.B = bb;

differentdbcontext.SaveChanges();

Если вы не хотите загружать оригинал из БД, требуется некоторое хитрое программирование:

var bb = // get existing bb from somewhere out-of-context

if (  (a.B == null && bb != null) 
   || (a.B != null && bb == null)
   || (a.B != null && bb != null && a.B.Id != bb.Id)) //take care not to attach
                                                      //two objects with same key
{
    if (bb != null)
        differentdbcontext.Set<B>().Attach(bb);
    differentdbcontext.Set<A>().Attach(a);
    a.B = bb; // EF will detect this change
}
else if (a.B == null && bb == null)
{
    // create a dummy a.B
    a.B = new B(); // it doesn't matter which Id
    differentdbcontext.Set<A>().Attach(a);
    a.B = bb; // = null -> EF will detect a change
}

differentdbcontext.SaveChanges();

или аналогичный. Идея состоит в том, чтобы изменить ссылку после присоединения объектов, чтобы обнаружение изменений отправляло обновление столбца FK в базу данных.

Использование внешних ключей в качестве свойств вашей модели значительно облегчит эту ситуацию. Установка состояния на Modified будет работать тогда, потому что свойства FK являются скалярными.

...