Чистый способ обработки циркулярных ссылок в EF?
Скажем, у меня есть эта структура таблицы:
Client
-----------
ClientId int not null (identity)
CurrentDemographicId int null (FK to ClientDemographic)
OtherClientFields varchar(100) null
ClientDemographic
------------------
ClientDemographicId int not null (identity)
ClientId int not null (FK to Client)
OtherClientDemographicFields varchar(100) null
Идея заключается в том, что Client (в EF) будет иметь список ClientDemographics и свойство CurrentDemographic.
Проблема заключается в том, когда я настраиваю структуру объекта и пытаюсь его сохранить, я получаю эту ошибку:
Невозможно определить действительное упорядочение для зависимых операций. Зависимости могут существовать из-за ограничений внешнего ключа, требований к модели или сохраненных в магазине значений.
Эта ошибка имеет смысл. У меня есть круговая ссылка в моей настройке таблицы. Он не знает, какой объект вставить сначала (потому что он одновременно должен иметь идентификатор из обеих таблиц).
Итак, я взломал решение, которое выглядит так:
// Save off the unchanged ClientDemograpic
ClientDemographic originalClientDemographic = client.CurrentClientDemographic;
// Merge the contract into the client object
Mapper.Map(contract, client);
// If this is a new client then add as new to the list.
if (client.ClientId == 0)
{
dataAccess.Add(client);
}
// Restore the original ClientDemographic so that EF will not choke
// on the circular reference.
ClientDemographic newClientDemographic = null;
if (client.CurrentClientDemographic != originalClientDemographic)
{
newCurrentClientDemographic = client.CurrentClientDemographic;
client.CurrentClientDemographic = originalClientDemographic;
}
// save our changes to the db.
dataAccess.SaveChanges();
// Restore updates to ClientDemographics and save (if needed)
if (newClientDemographic != null)
{
client.CurrentClientDemographic = newCurrentClientDemographic;
dataAccess.SaveChanges();
}
Но изменение ссылки обратно на предыдущее значение, сохранение, а затем установка его снова, чтобы я мог снова сохранить, чувствует себя как хак.
Есть ли более чистый способ справиться с циклическими ссылками в EF?
Ответы
Ответ 1
Я бы сказал, что ответ: "Не совсем". Единственный чистый способ справиться с круговой ссылкой - снова взглянуть на дизайн и удалить его.
В этом случае - приближаясь к нему с точки зрения Domain Driven Design - я бы сказал, что Client
- это корень вашего агрегата, а ClientDemographic
- объект значения; ClientDemographics
определяются значениями их "Другие поля ClientDemographic". Поэтому вы можете удалить ClientId
из ClientDemographic
, и проблема не будет устранена.
Тем не менее, если вы решились на эту структуру, то, к сожалению, я не думаю, что там есть аккуратный способ обработки в EF, no.
Изменить. Чтобы дать Client
multiple ClientDemographics
, а также свойство CurrentClientDemographic
, вы можете пойти другим путем; удалите CurrentClientDemographicId
из Client
и добавьте двоичное поле IsCurrent
к ClientDemographic
. Затем EF дает вам свойство коллекции ClientDemographics
, и вы можете добавить следующее в новый, неполный класс:
public partial class Client
{
public ClientDemographic CurrentDemogaphic
{
get { return this.ClientDemographics.First(cd => cd.IsPrimary); }
}
}
Ответ 2
Простым способом избежать этой ошибки является создание первичного объекта сначала, SaveChanges, а затем создание зависимого объекта перед вызовом SaveChanges снова.
В этом случае сначала создайте Client, SaveChanges, затем создайте объект ClientDemographic, добавьте его в коллекцию и снова установите в качестве CurrentDemographic, а затем SaveChanges.