Я попытался найти SO, но все результаты, которые я обнаружил, похоже, касаются обновления PK сущностей, которые уже были сохранены в БД. Мой случай другой.
У меня есть 3 таблицы в базе данных с отношениями 1-0..1. Отношения выглядят так:
A <- B <- C
где '<-' представляет отношение и указывает на основной конец. То есть у каждого B всегда есть связанный A, но у A не может быть B. Другими словами, мощность A равна 1, а B - 0..1. </p>
Каждое отношение представлено 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
, и я не смог сменить их PK. Но это не тот случай, оба объекта были созданы.
Я не могу разорвать цепочку ключей, используя отдельные столбцы PK для FK, потому что EF требует, чтобы обе стороны отношения 1-1 были PK.
Я не хочу синхронизировать ключи вручную, потому что на самом деле существует больше 1-1 связанных таблиц, и для этого потребуется код синхронизации появляться во многих местах.
Полагаю, я смогу обновить шаблон T4 генератора STE, чтобы каскадно обновлять PK до 1-1 отношений. Но я не слишком знаком с T4 и не очень рад это делать.
У меня есть 2 вопроса:
- Является ли мое ожидание каскадных обновлений PK в моем случае неправильным по некоторым причинам? (Кажется странным, хотя) То есть, это ошибка или особенность?
- Существуют ли другие и желательно более простые способы решения проблемы, чем изменение шаблона STE? Может быть, какие-то магические опции в отображениях EF или в контексте?
Заранее спасибо.