Entity Framework- Добавление объектов (и их свойств навигации) с общими первичными ключами
Это упрощенная версия проблемы, которую я пытаюсь решить:
Есть две сущности:
Вещь
ItemID (PK)
Другие простые свойства...
WorkItem (свойство навигации)
Рабочий элемент
ItemID (PK)
Другие простые свойства...
Item (свойство навигации)
Мне нужно создать Item, WorkItem для него, и мне нужно установить оба свойства навигации, чтобы эти два объекта могли указывать друг на друга перед сохранением.Это я могу сделать:
Item newItem = Item.CreateItem(0, blah,blah,blah);
service.AddToItems(newItem);
WorkItem newWorkItem = new WorkItem();
service.AddToWorkItems(newWorkItem);
//set the navigation properties
newItem.WorkItem = newWorkItem;
newWorkItem.Item = newItem;
К сожалению, когда дело доходит до сохранения, это терпит неудачу. Я полагаю, что EF при попытке установить ассоциацию элемента WorkItem пытается установить первичный ключ WorkItem.
Кто-нибудь может просветить меня о том, как правильно добиться этого, пожалуйста?
Обновить:
Итак, я попытался построить модель с использованием наследования. Модель строит и проверяет.
К сожалению, добавление службы данных WCF для моей модели и попытка просмотра службы в браузере дает мне следующее:
..... <m:message xml:lang="en-US">An error occurred while processing this request. </m:message>
<m:innererror>
<m:message>Navigation Properties are not supported on derived entity types. Entity Set 'app_Items' has a instance of type 'tempmodel.app_CostItem', which is an derived entity type and has navigation properties. Please remove all the navigation properties from type 'tempmodel.app_CostItem'.</m:message>
<m:type>System.InvalidOperationException</m:type>
<m:stacktrace> at System.Data.Services.Serializers.SyndicationSerializer.WriteObjectProperties(IExpandedResult expanded, ......
CostItem - это другая сущность, такая как WorkItem, которая наследуется от Item.
2 ответа
Я решил создать фиктивное свойство в каждом из моих частичных подклассов на стороне клиента:
private Item _BaseItem;
[AtomIgnore]
internal Item BaseItem
{
get
{
if (_BaseItem != null)
return _BaseItem;
else
return this.Item;
}
set
{
_BaseItem = value;
OnPropertyChanged("Item");
}
}
Код на стороне клиента использует это свойство BaseItem для обратного прохождения графа объекта. Таким образом, код для установки отношений теперь выглядит так:
Item newItem = Item.CreateItem(0, blah,blah,blah);
service.AddToItems(newItem);
WorkItem newWorkItem = new WorkItem();
service.AddToWorkItems(newWorkItem);
//set the navigation properties
newItem.WorkItem = newWorkItem;
newWorkItem.**BaseItem** = newItem;
Обратите внимание, что свойство BaseItem объявлено внутренним; это так, что сериализатор не будет пытаться сериализовать свойство и отправить его на сервер.
[AtomIgnore] - это атрибут, который я создал и ищу в своем обработчике для DataServiceContext.WritingEntity. Обработчик удаляет свойства, помеченные этим атрибутом, до их отправки на сервер. Эта техника, похоже, не работает, если свойство относится к типу ref, поэтому используется внутреннее.
Объявление его внутренним также означает, что его нельзя связать с XAML, к счастью, мне нужно было привязать только пару свойств, чтобы обойти это было просто.
Исходя из приведенного вами примера, я считаю, что вы должны использовать наследование. Сущность WorkItem должна наследоваться от сущности Item. Тогда в вашем коде вам нужно будет работать только с сущностью WorkItem, и она будет также иметь все свойства сущности Item. Кроме того, сущность WorkItem будет использовать ключ от сущности Item.