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.

Другие вопросы по тегам