Я попытался найти SO, но все результаты, которые я нашел, похоже, касаются обновления PK объектов, которые уже были сохранены в БД. Мое дело другое.Несколько взаимосвязанных отношений 1-1 не синхронизируют ПК как ожидалось
У меня есть 3 таблицы в базе данных с отношениями 1-0..1. Отношения выглядеть следующим образом:
A <- B <- C
где «< -» представляет собой связь и указывает на основной цели. То есть каждый B всегда имеет родственный A, но A может не иметь B. Другими словами, мощность A равна 1, а B - 0..1.
Каждая взаимосвязь представлена FK, которая переходит от PK дочернего объекта к PK родительского объекта. Каждый PK представляет собой столбец uniqueidentifier
Id
с клиентским значением. Я создал модель EF 4 из базы данных, которая имеет те же отношения с той же мощью.
Я пытаюсь добавить дочерние элементы B
и C
к существующему объекту A
. По соображениям дизайна пара новых экземпляров создается в одном мире кода, а объект A
связан с объектом B
в другом. Кроме того, я не хочу, чтобы последний знал, что существует C
.
Вот как код B
и C
создания выглядит следующим образом:
public B CreateB()
{
return new B
{
Id = Guid.NewGuid(),
C = new C(),
};
}
А теперь по ссылке и сохранить код:
// a is an instance of A that has been loaded from DB
// and hence has a persistent Id value.
// b is a just-created instance of B
// that has a non-persistent Id value and null reference to A.
void SaveBlahBlahBlah(A a, B b)
{
// At this point b and c have the same Id value.
// It differs from a's Id, but that's expected, they haven't been linked yet.
b.A = a;
// At this point b receives a's Id value, but c keeps the original one,
// therefore the existing b-c link gets broken!
using(var ctx = new MyContext())
{
ctx.As.Attach(a); // This throws exception saying
// I've violated referential integrity.
// It doesn't say which relationship is broken,
// but I guess it's the B-C one since
// the debugger shows them to have different values if PKs
ctx.Bs.AddObject(b);
ctx.SaveChanges();
}
}
Я попытался это и с генератором по умолчанию EF в коде (тот, который использует класс EF Entity
в качестве базового класса для сгенерированных объектов) и с генератором кода Self-Tracking Entities. Результат тот же.
Итак, код падает. Причиной может быть то, что после того, как A
и B
были связаны, B
и C
получают разные значения PK, которые являются незаконными для объектов с отношением 1-1.
То, что я ожидал, было C, чтобы автоматически получить его PK, синхронизированное со значением B
, полученным от экземпляра A
. Это кажется разумным, потому что я работаю с графиком объекта, у меня есть существующее отношение B
- C
, которое в порядке, и я ожидаю, что он останется ОК после ссылки B
с A
. Почему это сломается? Я бы это понял, если в базе данных существовали B
или C
, и я не смог изменить их ПК. Но дело обстоит не так, обе идеи были созданы.
Я не могу разбить цепочку ключей, используя отдельные столбцы PKs для FK, потому что EF требует, чтобы обе стороны отношения 1-1 были PK.
Я не хочу синхронизировать ключи вручную, потому что на самом деле существует более 1-1 связанных таблиц, и для этого потребуется, чтобы код синхронизации отображался во многих местах.
Я считаю, что смогу обновить шаблон T4 генератора STE, чтобы каскадировать обновления PK вниз по отношениям 1-1. Но я не слишком хорошо знаком с T4 и не слишком счастлив сделать это.
У меня 2 вопроса:
- Это мое ожидание каскадных обновлений PK в моем случае неправильно по некоторым причинам? (Кажется, странно, хотя) I.e., это ошибка или особенность?
- Есть ли другие и, возможно, более простые способы устранения проблемы, чем изменение шаблона STE? Может быть, некоторые магические варианты в EF-сопоставлениях или контекстах?
Заранее спасибо.
+1 Очень ясное объяснение! –
Спасибо. Я должен отметить, что я использовал «Attach», потому что без него EF попытался вставить 'A', что привело к ошибке, поскольку' A' уже существовал в БД. С тех пор я изменил модель и аромат (я использовал EFCF). Поэтому, возможно, ваше предложение будет работать, я попробую. –
Вы можете использовать 'Attach', но вам нужно сделать это * до * вы делаете отношения с B. –