Всемогущий, Google, найди мне чего-нибудь!

суббота, 15 января 2011 г.

Table-per-Type (EntityFramework)

Сегодня будем рассматривать иерархическую структуру данных для ORM Entity Framework. Сразу хочу оговориться, что ORM относительно молодая по сравнению с nHibernate, но уже успела впечатлить меня тем, что для неё есть встроенный редактор! :)

Итак, сразу к делу. Есть 3 вида компаний: Клиент (Client), Производитель (Manufacturer) и Подрядчик (Contractor). Структура базы будет следующей (Данные об этих сущностях будут сразу сведены к минимуму):

Рис. 1. Упрощенная структура базы данных.



Невооруженным глазом понятно, что будущий класс Company будет абстрактным. Теперь, самое интересное. Переходим в Visual Studio (у меня 2010). Создаем специфический проект, который предназначен специально для такого случая, как динамические данные. Данный вид шаблона очень удобен для админок и не только! :)

Рис. 2. Создание проекта.

Про данный шаблон необходимо начинать отдельную статью, посему сперва по теме.
После того, как был создан проект, необходимо "скормить" ему наши сущности. Для начала добавим ADO.NET Entity Data Model и добавим необходимые сущности:

Рис. 3. Добавление ADO.NET Entity Data Model.

Далее, указываем сгенерировать нам структуру из существующей базы данных. У меня сервер базы данных поднят на виртуальной машине, поэтому не пугайтесь страшного названия:

Рис. 4. Указание базы данных.

Рис. 5. Указание сущностей, необходимых для загрузки.

Вот что нам сгенерировали:

Рис. 6. Сгенерированная структура бизнес-моделей.

Но тут одна проблема. С первого взгляда её не заметить, НО учитывая, что структура базы данных и структура бизнес-моделей немного отличается. Посему, дабы всё работало как надо, сперва удалим связи и удалим из каждой дочерней таблицы удалим колонку CompanyId:

Рис. 7. Первичное изменение структуры.

Сперва добавим наследование. Правой кнопкой на таблице Company, потом Add -> Inheritance:

Рис. 8. Добавление наследования.

Необходимо сделать наследование для всех классов. После этого получим следующее:

Рис. 9. Добавленное наследование.

Теперь необходимо, чтобы колонка CompanyId в дочерних таблицах отмаппилось на колонку Id в родительской таблице (необходимо будет проделать для каждой дочерней таблицы):

Рис. 10. Маппинг первичного ключа.

Теперь необходимо "скормить" наши сущности. Идем в Global.asax.cs и ищем строчку:
//DefaultModel.RegisterContext(
//   typeof(YourDataContextType), 
//   new ContextConfiguration() { ScaffoldAllTables = false });
Меняем на:
DefaultModel.RegisterContext(
   typeof(DemoCompanyDatabaseEntities), 
   new ContextConfiguration() { ScaffoldAllTables = true });
Данное изменение обеспечивает наш шаблон источником данных. То есть шаблон динамических данных будет вытягивать нужную ему информацию из него. В нашем случае источником данных является DemoCompanyDatabaseEntities.
!IMPORTANT: Не забываем в редакторе в свойствах сущности Company поставить свойство Abstract в True.

Собсна всё. Теперь запускаем проект и смотрим плоды нашего творчества. Будут вопросы - обращайтесь, но думаю, что всемогущий гугл вам ответит быстрее :)

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