У нас есть старенькое веб приложение DXLibrary для учета литературы и поиска интересных пополнений в местной библиотеке, написанное много лет назад за пару часов одним из разработчиков на DevExpress eXpressApp Framework (XAF). Данные приложения хранятся в Microsoft SQL Server, а работа с ними ведётся через DevExpress eXpress Persistent Objects ORM (XPO). Так как сие чудо до сих пор сносно выполняет свои незаурядные функции, мне захотелось немного освежить его интерфейс под текущие реалии. Помимо украшательства хочется сменить XPO под капотом на Microsoft ADO.NET Entity Framework (EF). Основным мотивом тут для меня является не то, что EF чем-то лучше или хуже (обе ORM давно доказали, что отлично подходят для своих задач), а то, что до сих пор на Хабре не было русскоязычного руководства по интеграции XAF и EF, хотя они уже «не первый год замужем». Есть огромное желание восполнить этот пробел + элементарно хочется реализовать несколько недавних запросов от пользователей «библиотекаря». Наконец, с версии 15.1 XAF предоставляет обновлённый веб интерфейс, адаптированный в том числе для touch-устройств, который хотелось бы лишний раз показать сообществу, что греха таить:-)
Это первая и вводная часть из серии постов, где я попытаюсь показать по шагам вариант ускоренной генерации как веб, так и настольных line-of-business (LOB) приложений по существующей базе данных (БД) либо готовой модели EF, представляющей структуру вышеописанной предметной области. Пользовательский интерфейс будет создаваться автоматически на базе микса технологий ASP.NET WebForms/HTML5 и WinForms, а также соответствующих визуальных компонент DevExpress, скомпонованных вместе в рантайм под чутким руководством XAF. XAF — это наш модульный MVC фреймворк, а, по сути, сложившийся за почти 10 лет существования и постоянно расширяемый набор best patterns & practices для быстрого создания Office-like бизнес приложений для .NET разработчиков (узнать больше на Хабре, сайте).
Минимальные требования для прохождения
1. .NET Framework 4+ и Visual Studio 2010+ (поддерживаются полные и Community Edition версии, кроме express) – далее я буду использовать Visual Studio 2013.
2. Entity Framework 6 Tools (в зависимости от версии Visual Studio могут быть уже встроенными либо требовать отдельной установки)
3. Полная версия DevExpress Universal v15.1, либо 30-дневная пробная, которая качается с нашего сайта бесплатно, без регистрации и СМС:-) и ставится за пару минут на SSD. Если у вас вдруг есть доступ к v15.2 Beta, то лучше ее и использовать.
4. Microsoft SQL Server для хранения данных (подойдут любые полные/express/localdb версии, начиная с 2000) либо другой провайдер БД, поддерживаемый EF.
5*. Не лишним также будет общее знакомство с EF и понимание основных принципов object-relational mapping (ORM) и Model-View-Controller (MVC), лежащих в основе работы с нашим фреймворком.
Шаги по созданию нового XAF решения с EF 6
0. Скачаем пробную версию DevExpress Universal с нашего сайта, дождёмся успешной установки;
1. Откроем Visual Studio и запустим мастер создания нового проекта с именем DXLibraryV2 через стандарное FILE | New | Project…, воспользовавшись поиском и выбрав XAF Solution Wizard (либо изначально вызвав специальное меню: DEVEXPRESS | All Platforms | New Project...)
2. В запустившемся мастере выберем платформу Windows и Web и нажмём Next
3. Выберем Entity Framework Code First для доступа к данным и нажмём Next
4. Выберем Authentication = Active Directory, что означает вход в приложение по текущему Windows пользователю, и нажмём Next
5. Завершим работу нажатием на Finish, так как пока нам не нужны больше никакие дополнительные модули
Основные части созданного XAF решения
В результате мастер создаст нам заготовки для будущих приложений согласно выбранным ранее настройкам:
В двух словах, у нас получилось:
Для удобства, проекты содержат подпапки с говорящими именами и readme.txt файлы, которые могут помочь не заблудиться новичкам (узнать больше...).
Если мы прямо сейчас запустим DXLibraryV2.Web и DXLibraryV2.Win из Visual Studio, то получим работающие приложения для веб браузера* и Windows десктопа, которые пока ничему особенному не обучены, ну разве что кроме CRUD управления пользователями, ролями и настройками системы безопасности – эдакая простенькая админка за минуту:
* Чтобы активировать новый веб стиль как на картинке выше, на момент данной публикации нужно дополнительно дописать метод WebApplication.SwitchToNewStyle в Session_Start. В будущем это не будет требоваться.
Дальше давайте разбираться, как получился данный базовый функционал, какие есть особенности, где тут спрятался EF и как нам его модифицировать в будущем под свои нужды.
Особенности EF интеграции
Прежде всего, основная поддержка EF в XAF реализована в сборках DevExpress.ExpressApp.EF.v15.1.dll (для .NET 4.0) и DevExpress.ExpressApp.EF.45.v15.1.dll (для .NET 4.5), которые автоматически ссылаются в XAF проектах в зависимости от версии .NET Framework. Если вы используете наш мастер по созданию проектов, то все необходимые EF зависимости добавляются автоматически. Если нет, то их всегда можно добавить в проекты стандартным способом через NuGet.
На момент написания статьи последняя XAF версия поддерживает EF 6, охватывая как code-based стратегии c использованием DbContext, так и устаревшую стратегию на базе ObjectContext и EntityObject (в старых версиях также есть поддержка EF 5). По статистике, среди наших пользователей популярность последнего подхода к разработке модели данных сильно уступает первому, а после слухов о вероятном убиении EDMX в следующей генерации EF думаю она вообще сойдёт на нет. Официальной поддержки последних бет EF 7 на данный момент у нас нет ввиду постоянных изменений, хотя уже ведутся работы в данном направлении. Сама по себе новая генерация EF уже сейчас содержит много интересных возможностей для нас и наших пользователей и выглядит очень перспективной.
Технически, работа с EF Code First подразумевает, что у нас должны быть POCO бизнес-классы, определяющие структуры нашей модели данных, и наследник от DbContext, содержащий необходимый набор типизированных коллекций бизнес сущностей DbSet, которые могут быть запрошены из базы. Вы ещё помните, что на 5м шаге мы выбрали тип аутентификации пользователей (AuthenticationActiveDirectory), тем самым активировав встроенный модуль системы безопасности (SecurityModule)? Так вот, в результате этого мастер проекта включил в нашего наследника DbContext (DXLibraryV2.Module\BusinessObjects\DXLibraryV2DbContext.cs) необходимые встроенные сущности User, Role (а также др. сервисные запчасти), объявленные в опциональной библиотеке DevExpress.Persistent.BaseImpl.EF.v15.1, идущей как часть стандартной поставки XAF и содержащей готовые классы для типовых случаев.
Вышеупомянутые сущности являются совершенно обычными POCO классами, определяющими какую-то структуру данных и логику, например:
Далее тип пользовательского DbContext либо ObjectContext (в случае EDMX стратегии) вместе с выбранной строкой соединения к базе данных, взятой из конфигурационных файлов исполняемых приложений, передаётся в EFObjectSpaceProvider при настройке доступа к данным в наследниках WebApplication (DXLibraryV2.Web\WebApplication.cs) или WinApplication (DXLibraryV2.Win\WinApplication.cs).
WxxApplication классы представляют из себя исполняемые приложения для каждой из платформ и связанные с ними сервисы. Их экземпляры создаются и настраиваются при каждом запуске во входных точках приложений, например в методе Session_Start из DXLibraryV2.Web\Global.asax.cs или методе Main из DXLibraryV2.Win\Program.cs. Среди необходимых настроек приложения помимо компонентов системы безопасности и строки соединения присутствует список зависимых модулей, который может состоять как из сторонних так и из наших собственных модулей, например типа DXLibraryV2Module (DXLibraryV2.Module\Module.cs). XAF модули (наследники от ModuleBase), как и сами приложения (наследники XafApplication) являются настраиваемыми производными от System.ComponentModel.Component, для которых также доступны визуальные дизайнеры.
Специально для первого запуска приложений мастером был закодирован тестовый набор данных в методе UpdateDatabaseAfterUpdateSchema наследника ModuleUpdater (DXLibraryV2.Module\DatabaseUpdate\Updater.cs) — аналога метода Seed у EFских database initializerов.
В результате отработки методов ModuleUpdater-ов и связанного кода фреймворком была создана новая база данных на Microsoft SQL Server и соответствующие таблицы с записями:
EFObjectSpaceProvider независимо от выбора code-based или EDMX стратегий работает с ObjectContext API, являющимся для них общим знаменателем, ведь внутри DbContext в EF 6 пока ещё содержит в себе ObjectContext, доступ к которому можно получить через приведение к IObjectContextAdapter. В частности, мы используем его MetadataWorkspace для рефлексии информации о типах и их структуре для дальнейшего построения скелета CRUD пользовательского интерфейса.
Как вы могли заметить из примера кода в ModuleUpdater выше, в контексте XAF CRUD операции рекомендуется производить не напрямую через DbContext/ObjectContext, а через эту абстрактную сущность IObjectSpace или в нашем случае её конкретную реализацию для EF — EFObjectSpace. Он поставляется вышеупомянутым EFObjectSpaceProvider и использует у себя внутри ObjectStateManager и CreateQuery API, чтобы модифицировать или считывать данные. IObjectSpace, по сути, является ORM-независимым воплощением паттернов Repository и Unit Of Work, а технически просто оберткой над контекстом данных. Работая через IObjectSpace API, вы можете раз написав какую-то бизнес логику, мигрировать её на другую ORM без изменений. Более важно, что посредством IObjectSpace интерфейсная часть XAF взаимодействует с данными, например, получает их или «слушает» изменения и обновляет себя соответственно.
Практические заметки на будущее
1. Во время разработки и отладки приложения с тестовой БД после постоянных правок структуры дата модельных классов удобно временно отключать Code First Migrations фичу ЕF, прописывая нужный database initializer с помощью встроенного API из System.Data.Entity, например вот так (DXLibraryV2.Module\Module.cs):
2. Совсем не обязательно использовать встроенные классы User, Role из DevExpress.Persistent.BaseImpl.EF.v15.1– это в основном нужно новичкам для быстрого старта. XAF не является конечным продуктом и, в первую очередь — это гибкий и расширяемый *фреймворк* для построения приложений, в котором можно всегда заменить нужные запчасти на свои либо начать делать всё «с нуля», если уже знаешь, что да как. Так, например, вместо встроенных запчастей системы безопасности мы могли запросто объявить свои сущности согласно EF документации и добавить их в наш DbContext.
3. Для нормальной работы многих стандартных сценариев желательно реализовывать поддержку INotifyPropertyChanged в ваших бизнес классах (хоть вручную, хоть с помощью утилит типа этой, которые автоматически вставляют нужную реализацию во время компиляции). Ещё, как вариант, можно реализовать наш специальный интерфейс IObjectSpaceLink и руками звать ObjectSpace.SetModified(this), чтобы вызвать уведомление об изменении в нужных местах.
4. Из опыта, клиенты могут (и хотят) размещать бизнес логику прямо в самих EF классах вместо реализации отдельных контроллеров или сервисов. Не в нашем праве им запрещать (хотя на тему анемичной модели vs богатой на StackOverFlow куча холиваров, помню даже сам вбросил свои пять копеек тут) и для таких случаев помимо вышеупомянутого IObjectSpaceLink может быть удобен интерфейс IXafEntityObject, который облегчает написание логики на создании (OnCreated), загрузке (OnLoaded) и сохранении сущностей (OnSaving).
5. Если у вас осталась готовая библиотека EF классов от ASP.NET MVC проекта, вам может быть важно знать, что в данный момент у нас ограниченная поддержка стандартных Data Annotations атрибутов, влияющих на вид интерфейса, например DisplayFormat, UIHint. При этом стандартные атрибуты из EntityFramework.dll, System.ComponentModel.DataAnnotations.dll и других системных сборок, влияющие на поведение самого EF, работают как и должны, например StringLength, NotMapped, ComplexType. Как бы там ни было, в XAF есть куча своих универсальных атрибутов на любой вкус и цвет, которые позволяют ускорить настройку UI и связанной логики в простых случаях. Забегая вперед, стоит отметить, что, в общем, для такой задачи предпочтительнее использовать Application Model (вот тут уже рассказывал детальнее).
В заключение
Это, наверное, все основные особенности интеграции EF в XAF, о которых нужно знать на данном этапе. Углубить своё понимание можно с помощью нашей онлайн документации тут: eXpressApp Framework > Concepts > Business Model Design > Business Model Design with Entity Framework и eXpressApp Framework > Getting Started > Basic Tutorial (тут также содержится информация о фреймворке и основных подходах в общем). Также могут пригодиться демки XCRM, EFDemoCodeFirst, EFDemoModelFirst, которые можно найти в %Public%\Documents\DevExpress Demos 15.1\Components\eXpressApp Framework\ и которые представляют из себя довольно сложные и законченные приложения, демонстрирующие интеграцию почти со всеми модулями фреймворка. Куча примеров и ответов в базе знаний техподдержки также не будет лишней к упоминанию.
В следующей серии мы будем непосредственно создавать модель данных EF по существующей базе данных и также реализовывать основную логику работы исходного приложения-прототипа.
C уважением,
Денис
P.S.
Если вас заинтересовали наши продукты и после их более подробного изучения в течение бесплатного пробного периода вам захочется их приoбрeсти, то до 20 декабря 2015 года включительно вы можете воспользоваться дeсяти пpoцeнтным кyпонoм на пoкyпку в рyблях (~$220 или ~14тыc рyблeй по текущему курсу) новой лицензии DevExpress Universal, включающей в себя XAF и кучу других инструментов для разработки под популярные платформы. Для этого вам нужно будет перейти в мaгaзин Softline.ru и после оформления зaкaза
Отдельное спасибо нашему рeceллеру за то, что достаточно быстро удалось договориться об этой aкции на благо русскоязычного сообщества СНГ в такое время. Если вам вдруг удобнее кyпить в вaлюте напрямую с нашего сайта, то для получения аналогичной cкидки, напишите мне на почту с указанием ссылки на этот пост. Туда же можете присылать любые вопросы по XAF, пожелания или информировать о возможных проблемах.
Это первая и вводная часть из серии постов, где я попытаюсь показать по шагам вариант ускоренной генерации как веб, так и настольных line-of-business (LOB) приложений по существующей базе данных (БД) либо готовой модели EF, представляющей структуру вышеописанной предметной области. Пользовательский интерфейс будет создаваться автоматически на базе микса технологий ASP.NET WebForms/HTML5 и WinForms, а также соответствующих визуальных компонент DevExpress, скомпонованных вместе в рантайм под чутким руководством XAF. XAF — это наш модульный MVC фреймворк, а, по сути, сложившийся за почти 10 лет существования и постоянно расширяемый набор best patterns & practices для быстрого создания Office-like бизнес приложений для .NET разработчиков (узнать больше на Хабре, сайте).
Минимальные требования для прохождения
1. .NET Framework 4+ и Visual Studio 2010+ (поддерживаются полные и Community Edition версии, кроме express) – далее я буду использовать Visual Studio 2013.
2. Entity Framework 6 Tools (в зависимости от версии Visual Studio могут быть уже встроенными либо требовать отдельной установки)
3. Полная версия DevExpress Universal v15.1, либо 30-дневная пробная, которая качается с нашего сайта бесплатно, без регистрации и СМС:-) и ставится за пару минут на SSD. Если у вас вдруг есть доступ к v15.2 Beta, то лучше ее и использовать.
4. Microsoft SQL Server для хранения данных (подойдут любые полные/express/localdb версии, начиная с 2000) либо другой провайдер БД, поддерживаемый EF.
5*. Не лишним также будет общее знакомство с EF и понимание основных принципов object-relational mapping (ORM) и Model-View-Controller (MVC), лежащих в основе работы с нашим фреймворком.
Перед тем как начать, мои размышления на тему такого рода фреймворков, возможностей кастомизации и выбора ORM
Важно понимать, что XAF, по своей сути, не является code generator, как, например, наши похожие продукты DevExpress MVVM Framework & Scaffolding Wizard для WPF/WinForms. Напротив, XAF является самым настоящим динамическим application framework, который генерирует пользовательский интерфейс по неким правилам полностью во время исполнения. Так вам не придётся руками перезапускать генерацию форм после каждого изменения вашей исходной модели данных (таких как добавление нового класса или свойства) или терять ранее написанный в сгенерированных формах кастомный код — после запуска XAF приложения вы всегда автоматически получите актуальный результат "scaffolding" UI и БД по вашей текущей структуре данных и набору правил. Практически это означает, что по умолчанию в XAF не генерируется никакой исходный код CRUD форм, к которому разработчик бы имел прямой доступ в Visual Studio, как это происходит в обычной разработке клиентских приложений. Хотя разработчик XAF все-таки имеет полный контроль над конечными кирпичикам UI типа System.Windows.Forms.Control или HTML элементами и может ими манипулировать как в любом другом .NET приложении, большую часть времени типовой процесс XAF разработки представляет из себя настройку системы на более высоком уровне, часто через структуры дата моделей, кросс-платформенные XML настройки UI в дизайнере или через абстракции над UI элеметами в коде. Повторюсь, что доступ на низкий уровень есть, вас никто не ограничивает, можно также миксовать подходы, но требуется это намного реже, а иначе какой тут выигрыш по сравнению с традиционной разработкой? Должен признаться, что в этом и заключается одновременно самая большая прелесть и недостаток XAF, так как поначалу людям сложно перестроиться и абстрагироваться от оперирования визуальными контролами напрямую. Отсюда и крутая кривая обучения на первых этапах.
Наверное, также сразу стоит развеять сомнения по поводу возможностей UI и кастомизации под различные нужды заказчика в такого рода RAD инструментах, как говорится, не квадратно-гнездовым единым! Чтобы лучше представить UI типовых бизнес приложений, которые могут быть созданы с помощью фреймворка, можно посмотреть готовые иллюстрации на странице продукта тут, поиграть вживую с демонстрационными приложениями онлайн (или лучше из установщика, чтобы заодно захватить и десктопные версии) и, наконец, поглядеть в Интернете примеры production приложений от реальных заказчиков, например, вот хороший пример или вот парочка от знакомой многим в СНГ Галактики с их AMM, CnP, EAM и др. решениями (раз, два). Последние, кстати, вышли из «галактического» тюнинг-ателье:-) XAFARI — набора дополнительных модулей и компонет под платформу XAF. Помимо коммерческих third-party расширений, нельзя не упомянуть и бесплатный проект http://www.expandframework.com, который уже 5 лет развивается силами сообщества. Тут же отмечу, что во многом благодаря использованию визуальных компонент DevExpress работать с созданными приложениями вполне возможно, как и на обычном десктопе, так и на touch-устройствах с меньшим экраном, например, планшетах, при минимуме дополнительных настроек со стороны разработчика (причём даже в старом-добром WinForms!), но об этом позже.
Если у вас ещё нет готового багажа знаний какой-то ORM, то прежде чем начать работу с XAF, вы наверняка будете мучаться сложным выбором. С одной стороны, имеем дело с XPO — простой и до сих пор здравствующей проприетарной ORM библиотекой (узнать больше из русскоязычных обзоров сообщества: раз, два), которая c 2006 года была единственной выбором для XAF, с огромным числом примеров, документации, видео, бесплатной гарантированной поддержкой от компании-разработчика, а с другой — рекомендуемая open source технология для доступа к данным для .NET с бОльшим числом разработчиков на рынке труда, хорошим продвижением и развитием от Microsoft, поддержкой сторонних компаний, а также не меньшей базой знаний и технической поддержкой силами сообщества на StackOverFlow, Social.MSDN, forums.asp.net (правда, без гарантии быстрого ответа либо ответа вообще). Мы проводили опросы среди своих новых пользователей и оказалось, что для многих при прочих равных довольно существенным фактором при выборе технологии оказывается наличие гарантированной технической поддержки (здесь имеется ввиду помощь в случае проблем или вопросов по тому, как лучше сделать), а не то, что где-то там больше или меньше каких-то функций. Технически, если не брать во внимание факт, что формально EF поддерживается XAF позже XPO — с 2012 года, то поддержка двух библиотек на уровне самого XAF и его модулей сравнима по функционалу и охватываемым сценариям. В данный момент доля наших EF пользователей растёт, но все ещё прилично уступает XPO. Думается, релиз EF 7 и также выравнивание по наличию примеров на нашей стороне ещё изменит данное соотношение. Больше мыслей и отзывов наших пользователей на данную тему можно найти в моём блоге по теме.
Наверное, также сразу стоит развеять сомнения по поводу возможностей UI и кастомизации под различные нужды заказчика в такого рода RAD инструментах, как говорится, не квадратно-гнездовым единым! Чтобы лучше представить UI типовых бизнес приложений, которые могут быть созданы с помощью фреймворка, можно посмотреть готовые иллюстрации на странице продукта тут, поиграть вживую с демонстрационными приложениями онлайн (или лучше из установщика, чтобы заодно захватить и десктопные версии) и, наконец, поглядеть в Интернете примеры production приложений от реальных заказчиков, например, вот хороший пример или вот парочка от знакомой многим в СНГ Галактики с их AMM, CnP, EAM и др. решениями (раз, два). Последние, кстати, вышли из «галактического» тюнинг-ателье:-) XAFARI — набора дополнительных модулей и компонет под платформу XAF. Помимо коммерческих third-party расширений, нельзя не упомянуть и бесплатный проект http://www.expandframework.com, который уже 5 лет развивается силами сообщества. Тут же отмечу, что во многом благодаря использованию визуальных компонент DevExpress работать с созданными приложениями вполне возможно, как и на обычном десктопе, так и на touch-устройствах с меньшим экраном, например, планшетах, при минимуме дополнительных настроек со стороны разработчика (причём даже в старом-добром WinForms!), но об этом позже.
Если у вас ещё нет готового багажа знаний какой-то ORM, то прежде чем начать работу с XAF, вы наверняка будете мучаться сложным выбором. С одной стороны, имеем дело с XPO — простой и до сих пор здравствующей проприетарной ORM библиотекой (узнать больше из русскоязычных обзоров сообщества: раз, два), которая c 2006 года была единственной выбором для XAF, с огромным числом примеров, документации, видео, бесплатной гарантированной поддержкой от компании-разработчика, а с другой — рекомендуемая open source технология для доступа к данным для .NET с бОльшим числом разработчиков на рынке труда, хорошим продвижением и развитием от Microsoft, поддержкой сторонних компаний, а также не меньшей базой знаний и технической поддержкой силами сообщества на StackOverFlow, Social.MSDN, forums.asp.net (правда, без гарантии быстрого ответа либо ответа вообще). Мы проводили опросы среди своих новых пользователей и оказалось, что для многих при прочих равных довольно существенным фактором при выборе технологии оказывается наличие гарантированной технической поддержки (здесь имеется ввиду помощь в случае проблем или вопросов по тому, как лучше сделать), а не то, что где-то там больше или меньше каких-то функций. Технически, если не брать во внимание факт, что формально EF поддерживается XAF позже XPO — с 2012 года, то поддержка двух библиотек на уровне самого XAF и его модулей сравнима по функционалу и охватываемым сценариям. В данный момент доля наших EF пользователей растёт, но все ещё прилично уступает XPO. Думается, релиз EF 7 и также выравнивание по наличию примеров на нашей стороне ещё изменит данное соотношение. Больше мыслей и отзывов наших пользователей на данную тему можно найти в моём блоге по теме.
Шаги по созданию нового XAF решения с EF 6
0. Скачаем пробную версию DevExpress Universal с нашего сайта, дождёмся успешной установки;
1. Откроем Visual Studio и запустим мастер создания нового проекта с именем DXLibraryV2 через стандарное FILE | New | Project…, воспользовавшись поиском и выбрав XAF Solution Wizard (либо изначально вызвав специальное меню: DEVEXPRESS | All Platforms | New Project...)
(показать...)
2. В запустившемся мастере выберем платформу Windows и Web и нажмём Next
(показать...)
3. Выберем Entity Framework Code First для доступа к данным и нажмём Next
(показать...)
4. Выберем Authentication = Active Directory, что означает вход в приложение по текущему Windows пользователю, и нажмём Next
(показать...)
5. Завершим работу нажатием на Finish, так как пока нам не нужны больше никакие дополнительные модули
(показать...)
Основные части созданного XAF решения
В результате мастер создаст нам заготовки для будущих приложений согласно выбранным ранее настройкам:
В двух словах, у нас получилось:
- DXLibraryV2.Module — один кросс-платформенный модуль, содержащий общий код для всех платформ (например, бизнес логика, модели данных, настройки метамодели UI, работа с базой и в редких случаях универсальные UI редакторы)
- DXLibraryV2.Module.Wxx — пара платформенно-зависимых модулей, где могут жить код и настройки, специфичные для какой-то из платформ
- DXLibraryV2.Wxx — по одному исполняемому приложению на каждую платформу, т.е. ASP.NET сайт и WinForms приложение. По умолчанию эти приложения будут соединяться с Microsoft SQL Server для хранения данных по connectionString из конфигурационных файлов приложений (Web.config и App.config).
Для удобства, проекты содержат подпапки с говорящими именами и readme.txt файлы, которые могут помочь не заблудиться новичкам (узнать больше...).
Если мы прямо сейчас запустим DXLibraryV2.Web и DXLibraryV2.Win из Visual Studio, то получим работающие приложения для веб браузера* и Windows десктопа, которые пока ничему особенному не обучены, ну разве что кроме CRUD управления пользователями, ролями и настройками системы безопасности – эдакая простенькая админка за минуту:
* Чтобы активировать новый веб стиль как на картинке выше, на момент данной публикации нужно дополнительно дописать метод WebApplication.SwitchToNewStyle в Session_Start. В будущем это не будет требоваться.
Дальше давайте разбираться, как получился данный базовый функционал, какие есть особенности, где тут спрятался EF и как нам его модифицировать в будущем под свои нужды.
Особенности EF интеграции
Прежде всего, основная поддержка EF в XAF реализована в сборках DevExpress.ExpressApp.EF.v15.1.dll (для .NET 4.0) и DevExpress.ExpressApp.EF.45.v15.1.dll (для .NET 4.5), которые автоматически ссылаются в XAF проектах в зависимости от версии .NET Framework. Если вы используете наш мастер по созданию проектов, то все необходимые EF зависимости добавляются автоматически. Если нет, то их всегда можно добавить в проекты стандартным способом через NuGet.
На момент написания статьи последняя XAF версия поддерживает EF 6, охватывая как code-based стратегии c использованием DbContext, так и устаревшую стратегию на базе ObjectContext и EntityObject (в старых версиях также есть поддержка EF 5). По статистике, среди наших пользователей популярность последнего подхода к разработке модели данных сильно уступает первому, а после слухов о вероятном убиении EDMX в следующей генерации EF думаю она вообще сойдёт на нет. Официальной поддержки последних бет EF 7 на данный момент у нас нет ввиду постоянных изменений, хотя уже ведутся работы в данном направлении. Сама по себе новая генерация EF уже сейчас содержит много интересных возможностей для нас и наших пользователей и выглядит очень перспективной.
Технически, работа с EF Code First подразумевает, что у нас должны быть POCO бизнес-классы, определяющие структуры нашей модели данных, и наследник от DbContext, содержащий необходимый набор типизированных коллекций бизнес сущностей DbSet, которые могут быть запрошены из базы. Вы ещё помните, что на 5м шаге мы выбрали тип аутентификации пользователей (AuthenticationActiveDirectory), тем самым активировав встроенный модуль системы безопасности (SecurityModule)? Так вот, в результате этого мастер проекта включил в нашего наследника DbContext (DXLibraryV2.Module\BusinessObjects\DXLibraryV2DbContext.cs) необходимые встроенные сущности User, Role (а также др. сервисные запчасти), объявленные в опциональной библиотеке DevExpress.Persistent.BaseImpl.EF.v15.1, идущей как часть стандартной поставки XAF и содержащей готовые классы для типовых случаев.
Вышеупомянутые сущности являются совершенно обычными POCO классами, определяющими какую-то структуру данных и логику, например:
Далее тип пользовательского DbContext либо ObjectContext (в случае EDMX стратегии) вместе с выбранной строкой соединения к базе данных, взятой из конфигурационных файлов исполняемых приложений, передаётся в EFObjectSpaceProvider при настройке доступа к данным в наследниках WebApplication (DXLibraryV2.Web\WebApplication.cs) или WinApplication (DXLibraryV2.Win\WinApplication.cs).
public partial class DXLibraryV2WindowsFormsApplication : WinApplication {
public DXLibraryV2WindowsFormsApplication() {
InitializeComponent();
}
protected override void CreateDefaultObjectSpaceProvider(CreateCustomObjectSpaceProviderEventArgs args) {
args.ObjectSpaceProvider = new EFObjectSpaceProvider(
typeof(DXLibraryV2DbContext),
TypesInfo, null,
args.ConnectionString
);
}
WxxApplication классы представляют из себя исполняемые приложения для каждой из платформ и связанные с ними сервисы. Их экземпляры создаются и настраиваются при каждом запуске во входных точках приложений, например в методе Session_Start из DXLibraryV2.Web\Global.asax.cs или методе Main из DXLibraryV2.Win\Program.cs. Среди необходимых настроек приложения помимо компонентов системы безопасности и строки соединения присутствует список зависимых модулей, который может состоять как из сторонних так и из наших собственных модулей, например типа DXLibraryV2Module (DXLibraryV2.Module\Module.cs). XAF модули (наследники от ModuleBase), как и сами приложения (наследники XafApplication) являются настраиваемыми производными от System.ComponentModel.Component, для которых также доступны визуальные дизайнеры.
Специально для первого запуска приложений мастером был закодирован тестовый набор данных в методе UpdateDatabaseAfterUpdateSchema наследника ModuleUpdater (DXLibraryV2.Module\DatabaseUpdate\Updater.cs) — аналога метода Seed у EFских database initializerов.
В результате отработки методов ModuleUpdater-ов и связанного кода фреймворком была создана новая база данных на Microsoft SQL Server и соответствующие таблицы с записями:
EFObjectSpaceProvider независимо от выбора code-based или EDMX стратегий работает с ObjectContext API, являющимся для них общим знаменателем, ведь внутри DbContext в EF 6 пока ещё содержит в себе ObjectContext, доступ к которому можно получить через приведение к IObjectContextAdapter. В частности, мы используем его MetadataWorkspace для рефлексии информации о типах и их структуре для дальнейшего построения скелета CRUD пользовательского интерфейса.
Как вы могли заметить из примера кода в ModuleUpdater выше, в контексте XAF CRUD операции рекомендуется производить не напрямую через DbContext/ObjectContext, а через эту абстрактную сущность IObjectSpace или в нашем случае её конкретную реализацию для EF — EFObjectSpace. Он поставляется вышеупомянутым EFObjectSpaceProvider и использует у себя внутри ObjectStateManager и CreateQuery API, чтобы модифицировать или считывать данные. IObjectSpace, по сути, является ORM-независимым воплощением паттернов Repository и Unit Of Work, а технически просто оберткой над контекстом данных. Работая через IObjectSpace API, вы можете раз написав какую-то бизнес логику, мигрировать её на другую ORM без изменений. Более важно, что посредством IObjectSpace интерфейсная часть XAF взаимодействует с данными, например, получает их или «слушает» изменения и обновляет себя соответственно.
Практические заметки на будущее
1. Во время разработки и отладки приложения с тестовой БД после постоянных правок структуры дата модельных классов удобно временно отключать Code First Migrations фичу ЕF, прописывая нужный database initializer с помощью встроенного API из System.Data.Entity, например вот так (DXLibraryV2.Module\Module.cs):
// Uncomment this code to delete and recreate the database each time the data model has changed.
// Do not use this code in a production environment to avoid data loss.
// #if DEBUG
// Database.SetInitializer(new DropCreateDatabaseIfModelChanges<DXLibraryV2DbContext>());
// #endif
2. Совсем не обязательно использовать встроенные классы User, Role из DevExpress.Persistent.BaseImpl.EF.v15.1– это в основном нужно новичкам для быстрого старта. XAF не является конечным продуктом и, в первую очередь — это гибкий и расширяемый *фреймворк* для построения приложений, в котором можно всегда заменить нужные запчасти на свои либо начать делать всё «с нуля», если уже знаешь, что да как. Так, например, вместо встроенных запчастей системы безопасности мы могли запросто объявить свои сущности согласно EF документации и добавить их в наш DbContext.
3. Для нормальной работы многих стандартных сценариев желательно реализовывать поддержку INotifyPropertyChanged в ваших бизнес классах (хоть вручную, хоть с помощью утилит типа этой, которые автоматически вставляют нужную реализацию во время компиляции). Ещё, как вариант, можно реализовать наш специальный интерфейс IObjectSpaceLink и руками звать ObjectSpace.SetModified(this), чтобы вызвать уведомление об изменении в нужных местах.
4. Из опыта, клиенты могут (и хотят) размещать бизнес логику прямо в самих EF классах вместо реализации отдельных контроллеров или сервисов. Не в нашем праве им запрещать (хотя на тему анемичной модели vs богатой на StackOverFlow куча холиваров, помню даже сам вбросил свои пять копеек тут) и для таких случаев помимо вышеупомянутого IObjectSpaceLink может быть удобен интерфейс IXafEntityObject, который облегчает написание логики на создании (OnCreated), загрузке (OnLoaded) и сохранении сущностей (OnSaving).
5. Если у вас осталась готовая библиотека EF классов от ASP.NET MVC проекта, вам может быть важно знать, что в данный момент у нас ограниченная поддержка стандартных Data Annotations атрибутов, влияющих на вид интерфейса, например DisplayFormat, UIHint. При этом стандартные атрибуты из EntityFramework.dll, System.ComponentModel.DataAnnotations.dll и других системных сборок, влияющие на поведение самого EF, работают как и должны, например StringLength, NotMapped, ComplexType. Как бы там ни было, в XAF есть куча своих универсальных атрибутов на любой вкус и цвет, которые позволяют ускорить настройку UI и связанной логики в простых случаях. Забегая вперед, стоит отметить, что, в общем, для такой задачи предпочтительнее использовать Application Model (вот тут уже рассказывал детальнее).
В заключение
Это, наверное, все основные особенности интеграции EF в XAF, о которых нужно знать на данном этапе. Углубить своё понимание можно с помощью нашей онлайн документации тут: eXpressApp Framework > Concepts > Business Model Design > Business Model Design with Entity Framework и eXpressApp Framework > Getting Started > Basic Tutorial (тут также содержится информация о фреймворке и основных подходах в общем). Также могут пригодиться демки XCRM, EFDemoCodeFirst, EFDemoModelFirst, которые можно найти в %Public%\Documents\DevExpress Demos 15.1\Components\eXpressApp Framework\ и которые представляют из себя довольно сложные и законченные приложения, демонстрирующие интеграцию почти со всеми модулями фреймворка. Куча примеров и ответов в базе знаний техподдержки также не будет лишней к упоминанию.
В следующей серии мы будем непосредственно создавать модель данных EF по существующей базе данных и также реализовывать основную логику работы исходного приложения-прототипа.
C уважением,
Денис
P.S.
Если вас заинтересовали наши продукты и после их более подробного изучения в течение бесплатного пробного периода вам захочется их приoбрeсти, то до 20 декабря 2015 года включительно вы можете воспользоваться дeсяти пpoцeнтным кyпонoм на пoкyпку в рyблях (~$220 или ~14тыc рyблeй по текущему курсу) новой лицензии DevExpress Universal, включающей в себя XAF и кучу других инструментов для разработки под популярные платформы. Для этого вам нужно будет перейти в мaгaзин Softline.ru и после оформления зaкaза
ввeсти в специальное поле кoд
Universal_XafEf
Отдельное спасибо нашему рeceллеру за то, что достаточно быстро удалось договориться об этой aкции на благо русскоязычного сообщества СНГ в такое время. Если вам вдруг удобнее кyпить в вaлюте напрямую с нашего сайта, то для получения аналогичной cкидки, напишите мне на почту с указанием ссылки на этот пост. Туда же можете присылать любые вопросы по XAF, пожелания или информировать о возможных проблемах.