11/11/2009 1:48:00 PM

В нашем проекте мы используем Entity Framework. Разумеется в первой, существующей ипостаси. Штука эта интересная и мощная, но имеет несколько существенных недостатков и неудобностей, среди которых и необходимость наследования всех классов от базового класса EF, и невозможность избавиться от Navigational Properties, и полное отсутствие контроля над поведением (да и интерфейсом) сгенерированных классов, и невозможность юнит-тестирования…

И если с классами немного удалось сладить, написав собственную утилиту-генератор, то вот всё остальное – просто беда. Да, существует такая штука, как TypeMock для юнит-тестирования, но во-первых, она платная для коммерческого использования, а во-вторых, работает через profiling API… Но хоть что-то.

В общем, поскольку нам была обещана приватная встреча с двумя ведущими разработчиками Entity Framework, я решил посмотреть немного, что обещается в следующей версии.

Очень приятным моментом для меня стало то, что Navigational Properties теперь из модели можно просто выкинуть.
Обратите внимание на скриншот: в классе Member нет свойства Member_Properties, в классе Member_Properties нет свойства Member. Это я их удалил :) При этом EF по-прежнему знает о связи этих двух сущностей и даже отображает её в дизайнере.

Navigational Properties можно удалить

Ещё одна приятная мелочь: “нормальные” ID-поля для ключей. Смотрите на Member_Addresses, свойства MemberId и AddressId - “обычные” int-свойства. Navigational Properties для Address и Member тоже есть, я их просто не удалял.

Вторым очень приятным моментом стала поддержка “обычных” классов. “POCO-классов”, как теперь модно говорить. POCO – это “Plain Old CLR Object”. То есть, в качестве entity теперь может выступать класс, не унаследованный от “специального” базового класса.
Это очень, очень, очень здорово!

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

Add Code Generation Item

Таких генераторов для модели можно иметь столько, сколько захочется и генерировать совершенно разные вещи.
Я в своём тестовом проекте просто удалил .designer.cs файл тестовой модели и отключил в свойствах .edmx-файла регенерацию. То есть, .edmx-файл теперь для меня просто описывает модель, которая может быть обновлена из БД, содержит все маппинги и т.д, но не генерирует сама по себе никаких .NET-классов.

Вместо этого я добавил Generation Item, который делает всю эту работу. Этот Generation Item представляет собой обычный .tt-файл, то есть, тот самый обычный темплейт, который существует в Visual Studio ещё с 2005-й версии, но о котором мало кто знает :) темплейт представляет собой простой текстовый файл, в котором на простом и понятном языке (например C#) просто и понятно описывается, как и что должно быть сгенерировано.
Вот, их даже два в моём проекте:

Templates Template file

Я не писал эти темплейты с нуля, но редактировать файл темплейта, например, дописать туда что-то нужное или убить что-то ненужное, очень легко, никаких особых знаний для этого не требуется.

В моём случае первый файл генерирует, собственно, контекст и всё, что с ним связано. Второй – сами entities.

Результат работы темплейтов Сгенерированный класс

При этом Entities, как я уже сказал, можно делать POCO-классами и, например, метить их DataContract/DataMember атрибутами, что позволяет использовать их в WCF и избежать часто ненужного маппинга между DTO и Entities. По сути мы имеем возможность сразу из БД получить нужные нам бизнес-объекты и DTO, что тоже очень здорово и очень облегчает жизнь.

Я уже сказал, что темплейты очень легко переделать на свой лад, чтобы они генерировали то, что нужно. Контроль над генерацией и возможность сгенерировать так, как нужно – важная вещь.
Генерируя те же entities можно ещё каких-то атрибутов навесить, или реализовать геттеры-сеттеры так, как хочется, или переопределить ToString(), или ещё методов добавить…

Я вот, задумавшишь о тестировании, добавил несколько строк в темплейт, чтобы он генерировал мне тот самый “TestModel.Context.Interfaces.cs”, который видно на картинке. Изначально его не было.
В этом файле я просто определяю интерфейс для контекста. Ну, ещё я поправил, чтобы класс контекста реализовал этот интерфейс, дописав “, ITestDbEntities” в сигнатуру класса :) 
Этот интерфейс будет используется при юнит-тестировании.

Интерфейс, он простой, смотреть сюда незачем

Предыдущая версия EF использовала в контексте некий класс EntitySet<>, который был абсолютно неудобен в случае юнит-тестирования, новая версия использует ObjectSet<>, который реализует интерфейс IObjectSet<>. А если есть интерфейс – значит можно делать мок! А раз можно делать мок – значит можно писать юнит-тесты!
То, что надо!

Да, нужно отметить, что каждый раз, когда меняется темплейт или меняется .edmx-файл модели, все относящиеся к ней темплейты перегенерируют то, что они там генерируют. То есть, следить за этим совершенно не надо.
Вы просто меняете то, что хотите поменять, остальное делается “само”: обновляются классы бизнес-модели, DTO, возможно классы менеджеров с примитивными методами типа LoadById, Save, какие-то рутинные классы преобразований и хелперов и т.д, и т.п.

Надо будет посмотреть на это дело поближе.

Powered by BlogEngine.NET 1.6.0.0

About the author

Alexey Raga Alexey Raga
.NET software developer.

E-mail me Send mail

Twitter


Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2010

Sign in