EF4 DB-first: подход TPH?

#entity-framework-4 #linq-to-entities #ef-database-first #database-first #table-per-hierarchy

#entity-framework-4 #linq-to-entities #ef-database-first #база данных-первая #таблица для каждой иерархии

Вопрос:

Я знаю, что это не должно быть тривиальным, но пока не смог найти решение…

Работа с моделью EF4 DB-First, использование LINQ-to-Entities с POCOs, которые будут использоваться приложением MVC3.

У меня есть три объекта Customer , CustomerAdress и поиск CustomerAddressType .

 Customer             CustomerAddress                  CustomerAddressType
----------           ----------------                 -------------------
CustomerId (PK)      CustomerAddressId (PK)           CustomerAddressTypeId (PK)
LastName             CustomerId (FK)                  Description (Values: Mailing, Billing)
FirstName            CustomerAddressTypeId (FK) 
MiddleInitial        Address
....                 City
                     State
                     Zip
                     StartDate
                     EndDate
  

Как вы можете видеть, CustomerAddress имеет FK CustomerAddressTypeId , который определяет, какой это тип адреса, т.е. для рассылки или для выставления счетов.

Я хотел бы:

  • Есть возможность сделать что-то вроде этого: Customer.CustomerAddress.OfType<MailingAddress> получить коллекцию почтовых адресов для клиента.
  • Иметь свойства CurrentMailingAddress и CurrentBillingAddress , которые в будущем возвращали бы единственный экземпляр CustomerAddress.OfType<> с наивысшим StartDate значением EndDate и, в конечном счете.
  • Было бы также неплохо использовать Address сквозные Zip свойства и преобразовать эти свойства в сложный тип Address .

Я попытался создать 2 унаследованных объекта из CustomerAddress (предполагая, что это стратегия TPH [таблица для иерархии]): MailingAddress и BillingAddress , CustomerAddressTypeId являющаяся дискриминатором. Я сделал это в конструкторе моделей, и как только я попытался добавить вторую унаследованную сущность, она сказала мне, что свойства с этими именами уже существуют, и не позволила мне переименовать их, чтобы они соответствовали свойствам первой сущности.

Есть идеи, как этого добиться? Пожалуйста, отключите это для меня 🙂 Спасибо!!!

Ответ №1:

Это не так тривиально. TPH будет возможен, но вы должны поместить все свойства в базу CustomerAddress и вывести две дочерние сущности, которые не будут содержать никаких свойств, потому что все свойства являются общими (= должны быть в родительском). Вы будете использовать CustomerAddressTypeId в качестве дискриминатора, и из-за этого вы не сможете отобразить это поле как свойство в сущности. Я также не уверен, что у вас может быть поле как в дискриминаторе, так и в сопоставлении ассоциаций (это на самом деле хорошая домашняя работа для меня). В противном случае вы не сможете сопоставить связь между CustomerAddress и CustomerAddressType .

Оба CurrentMailingAddress и CurrentBillingAddress являются вычисляемыми свойствами, и они не являются частью сопоставления. Вам решать реализовать их логику в вашей частичной части Customer сущности.

Я не понимаю последнего пункта с Zip и сложным типом.

Комментарии:

1. Спасибо, Ладислав. Думаю, отвечая на ваш пост, я начну с обратной стороны. 🙂 1) Address , City , State , Zip — Я хотел бы провести рефакторинг в сложный тип, но не был уверен, что это доставит мне огорчения в будущем (я думаю, что все должно быть в порядке). 2) Причина, по которой я упомянул текущий * адрес, заключается в том, что именно там я хотел бы использовать CustomerAddress. Тип<>. 3) Я попробую и дам вам знать, как я разбираюсь.

2. Хорошо, я создал 2 объекта CustomerBillingAddress и CustomerMailingAddress с базовым типом CustomerAddress . Установите отображение таблицы на CustomerAddress и столбец дискриминатора для каждого объекта CustomerAddressTypeId с соответствующим значением. Затем, когда я перехожу к проверке модели, я получаю следующую ошибку:

3. Error 1 Error 3023: Problem in mapping fragments starting at lines 1146, 1169, 1175:Column CustomerAddresses.AddressTypeId has no default value and is not nullable. A column value is required to store entity data. An Entity with Key (PK) will not round-trip when: (PK is in 'CustomerAddresses' EntitySet AND Entity is type [Entities.CustomerAddress]) . Я попытался удалить столбец дискриминатора ‘CustomerAddressTypeId` из базового объекта CustomerAddress , тем самым разорвав связь с CustomerAddressType , но все равно появляется то же сообщение.

4. Хорошо, я думаю, что я устранил ошибку проверки модели… Пришлось: 1) для объекта CustomerAddress изменить свойство на Abstract: True (для создания абстрактного класса); 2) Удалить объект CustomerAddressType ; 3) Удалить столбец дискриминатора CustomerAddressTypeId из базового объекта CustomerAddress . Пока не было возможности проверить в коде, что все работает так, как ожидалось, но скоро опубликую.

5. Хорошо, я наконец смог проверить, и это работает, но Ладислав, как вы упомянули, я не могу использовать оба способа, чтобы CustomerAddressTypeId быть одновременно ассоциацией и дискриминатором. Итак, мне пришлось потерять ассоциацию, что не имеет большого значения.