Entity Framework missing FAQ (Part 1).
- 1. Database First
- 1.1. Традиційні DB First без моделера Visual Studio
- 1.2. Вам допоможе Nuget.ORG
- 1.3. ObjectContext vs DbContext
- 1.4. Поширення EF
- 1.5. Довідники EF
- 2. Model First
- 2.1 Переваги Model First над Database First
- 2.2 Приклад
- 2.3 Схема моделі вбудована у ресурс DLL
- 2.4 Міграція (Package console/CMD utility/site code)
- 2.5 Публікація проекту з EF
- 2.6 Профайлер трансляции EF з Linq у SQL та EF Retry Policy (повний код проєкту)
- 2.7 Альтернативи мікрософтовському ModelFirst
Які взагалі переваги будь-якого ORM перед повною його відсутністю? На мій погляд існує лише одна перевага, синхронізація назв полей та Intelisence, якщо вам це не потрібно, ви можете працювати з базою наприклад так (new SqlDataSource).Select("select * from table1"). Це екстремально просто, якщо нічого зайвого крім даних з бази вам не потрібно. Відмовляючись від ORM ви лише відмовляєтесь від Intellisence та Linq. Хоча й це не обов'язково. Успіх проєкту ніяк не залежить від того, чи ви користуєтесь ORM, чи просто напрямки отримуєте дані з базу у свою програму. У мене наприклад є проект https://arenda.votpusk.ru/default.aspx, зроблений без будь яких ORM, лише на простих SqlDataSource працює більше 10-ти років і приніс сотні тисяч доларів користі його власникам (та мені трохи грошей за його супорт), а інші проєкти, зроблені на найновіших і могутніших ORM не працювали й року. Взагалі існує 4,164,044,800,000,000 варіантів побудувати ASP.NET сайт (якщо не рахувати нові засоби на NET CORE). Тому ще раз вщипніть себе за дупу й запитайте себе, чи взагалі мені потрібен будь-який ORM? Після цього запитайте себе - чи це повинен бути безкоштовний фреймворк від мікрософту, чи щось покраще? Якщо безкоштовний, то який саме? Чи необхідні вам Unit-тести та різноманітні SQL Engine? Якщо ні - беріть Linq-to-SQL, якщо потрібні тести та планується зміна SQL-сервера на протязі життя проекту, то за умов безкоштовності ORM - конкуренції EF немає. Отже, існують деякі виняткові ситуації, коли Entity Framework має переваги, більш детально почитайте тут - Умови використання Entity Framework.
Нище я покажу як взагалі можна використати та отримати яку-небудь користь від EF у тих виняткових ситуаціях, коли він взагалі має сенс. Для приклада даних, я узяв всесвітньо відомий приклад ContosoUniversity, який ви можете зкачати наприклад на моєму сайті ASP.NET documentation and samples (snapshot 2017). Я зробив цей снапшот, бо Мікрософт занадто нестабільна компанія, я дивлюсь на свої сторінки 10-ти, або 20-ти річної давності - й жоден лінк на Microsoft не працює! Я вже не кажу, що кожна наступна технологія, яку істерично намагається просувати Міскрософт, взагалі повністю спростовує будь які ствердження, які Мікрософт так само істерично стверджував, просуваючи свою попередню технологію. Тобто, на мою думку, Мікрософт працює за принципом - крок вперед, два назад - і увесь час підтирає за собою лінки на попередні ствердження. Але до біса Мікрософт, давайте подивимося, як можна вилучити будь яку користь з Entity Framework.
Отже перший скрін після утворення проєкту - самий найголовний, бо тут приймається головне рішення проєкту, яким чином ви плануєте утворювати свій проєкт, класичнім Database-First з дізайнером бази, Database-First з дизайнером VisualStudio (цей метод носить назву ModelFirst), або альтернативним - спочатку класи, а потім розгортати класи у базу (цей метод має назву Code-First). Все це дуже різні засоби, тому далі будуть чотири окремих розділу.
1. Database First
У цьому випадку ви користуєтесь традиційними інструментами, які існують вже 20-ть й більше років. Існують не тому, що не було занадто вумних мікрософтовських індусов, а тому, що все, що робилось до цього у світі, починаючи з атомної зброї та космічних кораблів робилося завжди традиційними методами, тобто спочатку робили базу, а потім робили код. Крок за кроком модифікуючи базу, якщо на це виникала потреба. Взагалі, якщо ви подивитесь на мою сторінку Класифікація засобів роботи з даними, то всі засоби роботи з даними, за винятком останнього - це саме DataBase First, лише у останньому пункті існує можливість вибрати альтернативний засіб проєктування.
1.1. Традиційні DB First без моделера Visual Studio
Головний інструмент при проєктуванні DataBase First - моделер, який існує у будь якій базі. Ну от наприклад як він виглядає у MS SQL (скрін для невеличких тестових даних).
Приблизно так само моделер виглядає у будь-якій DB-engine. Подивиться, наприклад, як він виглядає у PostgreSQL. Це мій власний проєкт на PostgreSQL (Используем PostgreSQL вместо MS SQL в проектах на NET и ASP.NET, ось тут, навіть, я кинув трохи кода з цього проєкту - Фрагмент реальной BLL на PostgeSQL
Нажаль моделер EF у VS2017 для реальної бази занадто повільно працює, наприклад я чекав біля години, поки він побудує модель реальної бази, але так і не дочекався. Дізайнер VS2015 побудував мені дізайн тієї ж самої бази за 15 хвилин, але вбудований дізайнер MS SQL будує дізайн майже миттєво.
1.2. Вам допоможе Nuget.ORG
Після утворення проекту з існуючого шаблону, у папці BIN з'явилися усі необхідні референси. Тут є цікава тема про шаблони проектів, що зберігає студія, як імпортувати проєкти, як утворювати свої власні типи проєктів Extensebility project, де вони зберігаються та як ях модифікувати. Це трохи виходить за межи цієї розповіді, можливо пізніше я щось напишу з цього приводу.
Далі Nuget.org додає необхідні залежності та референси на EntityFramework.dll коли ви додаєте до проекту EntityFramework. Nuget - це взагалі дуже цікава розповідь, нажаль це трохи виходе за рамки цієї сторінки, наразі я трохи оновив сторінку від 2010 року VS2010 package manager, можливо я пізніше опишу трохи детальніше як працює Nuget, як його встановити.
1.3. ObjectContext vs DbContext
Взагалі існує два різних метода кодогенерації. Перший з них має назву T4. Це "нова" концепція мікрософта, так званий макропроцессор. Коли я починав працювати більш 30-ти років тому, макропроцессор - це був головний засіб програмування. Ніхто і ніколи не використовував безпосередньо програмінг на Асемблері, всі писали макроси, яки будували ассемблерний код. Не пройшло й 30-ти років, як цю ідею зрозуміли мікрософтовскі індуси Generating Files with the TextTransform Utility.
Отже метод кодогенерації будує два VB-файла - один з буферами для пам'яті (так звані POCO-класи), а інший для контекста використання цих буферів DbContext.
Якщо ви змінюєте засіб кодогенерації на Legacy ви отримуєте головний сервісний файл ObjectContext, який додає вам багато можливостей, наприклад утворення нових об'єктів з умовами збереження контрейнсов, навігаційні можливості та інше. Метод кодогенерації змінюється з None на Default, а програмування з Legacy-контекстом більш нагадує програмування у більш могутніх ORM, таких як Linq-to-SQL.
DbContext при наявності Object-контексту з Legacy-кодом немає жодного сенсу, бо він занадто обмежений по можливостям. Але принципово його можливо додати окремо. хоча я не зовсім розумію навіщо це потрібно, ну мабуть якщо один програміст робив проєкт раніше у одному контексті, а ви звикли працювати у іншому.
Є ще декілька важливих галок, пов'язаних з особливостями роботи EF, наприклад галка прелоадінга даних.
Головне, що потрібно пам'ятати при здійсненні вибору між ObjectContext та DbContext.
А далі все просто, принципово програмування у EF нагадує програмування у будь-яких ORM, побудованих по принципам Linq-to-SQL, наприклад від DevArt. Ніякі додаткові можливості EF вам у випадку DataBase-First вам непотрібні, бо девелопмент даних ви виконуєте традиційнім засобом - безпосередньо у моделері базі, а у коді лише оновлюєте нову структуру бази.
1.4. Поширення EF
Ще одне питання, яке потрібно зрозуміти після цього топіку, що існує не тільки безліч альтернативних варіантів EF DB First (я наголосив це на початку цього топіка), але й існує безліч різноманітних додаткових поширень EntityFramework, починаючи з платних до безкоштовних, на скрині нище ви можете побачити яким чином отримати доступ до більшості з них.
Зверніть увагу, що більш розвинуті ORM, наприклад Linq-to-SQL від Devart без додаткових пакетів забеспечують і предкомпілені SQL-запроси і клієнтські PLINQ-поширення і рекурсію і багато чего ще.
1.5. Довідники EF
2. Model First
2.1 Переваги Model First над Database First
Коли я дивлюсь різноманітні описи переваг, щоб робити проєктування бази безпосередньо у студії, замість моделерів, які йдуть з двигуном бази, мені здається що я читаю якийсь божевільних. Що тільки вони не пишуть, навіть перераховувати та коментувати усі ці дурниці у стилі "у MSSMS робити моделі даних важко, а у студії ні" - це не поважати себе. Тому відразу перейдемо до суті речей. У яких випадках ModelFirst може бути корисною?
- По-перше, коли проєкт вже працює і юзера набили його мільйонами записів - ніякого сенсу у ModelFirst бути не може, бо щонайменьше оновлення бази (а у працюючому проєкті це робиться постійно) - щонайменше оновлення повністю знищить базу.
- По-друге, студія працює у тисячі разів повільніше, ніж наприклад MS SMS, і більш-менш нормальну базу (від тисячі табличок) студія у вигляді моделі взагалі не відкриє, скільки б ви не чекали.
- По-трете, EF дивиться на базу ЕКСТРЕМАЛЬНО спрощено, тобто як на сховище табличок. Це якесь mental disability так спрощено дивитися на базу, бо MS SQL база має крім табличок ще приблизно сто специфічних об'єктів (та ще більше специфічних типів даних). Точно так, Oracle має свої власні специфічні об'єкти. Ще більш специфічні об'єкти має MongoDB. Взагалі я не розумію індусів, які вирішили уніфікувати всі бази сховища табличок у межах стандарту SQL99 та навіть поширили його далі, до межі MongDB.
Тобто едина реальна перевага - це постійна СИНХРОНІЗАЦІЯ коду і структури бази у кожному патчі. Тобто ця схема ModelFirst має сенс у невеличких проєктах, у яких постійно змінюється структура бази, при чому постійно перекладається з Oracle на MySQL, з якого далі на PostgreSQL, потім на MS SQL, потім на DB2, потім на Sybase, потім на Firebird, потім на Informix, потім на SQLLite і далі по кругу по всім відомим двигунам баз даних, включно NoSQL DB, такі як MongoDB та ще більш кручені. При чому по GIT-схемі проєкту ви рухаєтеся не тільки вперед по Master-струму, а час від часу повертаєтесь відмовляєтесь від вже напрацьованого та повертаєтесь на попередню структуру бази. Так, насправді, у такому проєкті схема ModelFirst дійсно не має конкуренції. Згоден. Але я не розумію, що це може бути за проєкт, сорри. Я таких поки що не бачив.
2.2 Приклад
Отже, йдемо далі. Подивимося, як з цим можливо працювати. Утворюємо модель і яку-небудь найпростішу табличку.
2.3 Схема моделі вбудована у ресурс DLL
Схема EF вбудовується як ресурс утвореного DLL, щоб побачити це, спочатку зробимо якийсь екстремально простий сайтік у одну стрічку кода.
І зробимо компільовану версію нашого мега-сайтіку.
Працювати наш сайт поки що не буде, бо ми нічого не маємо у базі, навіть конект у нас кривий, лише до ресурсу, але у нас уже з'явився хоч якийсь бінарний код у файловій сістемі. А це й є наша мета, бо у коді вбудований цікавий нам ресурс, на який ми зараз подивимося очима.
Для цього відкриваємо утіліткою http://www.ilspy.net/ утворену DLL-ку і ось воно, спочатку откомпільований сайтік а далі ресурс з визначення нашої структури бази.
Так само можна прочитати визначення моделі за допомогою колись популярної програми LinqPad, принципово це та ж сама студія VS2017, але без дебагера, тому що результати Linq ви можете подивитись безпосередньо на головному вікні. До того ж з чудовими прикладами/шаблонами на будь-які випадки. Нажаль, наразі безкоштовно у LinqPad лише нікому непотрібні можливості, все більш-менш потрібно - вже за гроші.
Відповідність схеми моделі та реальної схеми бази перевіряється EF, і у разі невідповідності ви отримаєте помилку.
У будь який момент можливо оновити базу з модели, виконавши рефреш структури бази, ось наприклад тут йде мова про інший проєкт. Я додав у модель декілька полей, отримав помилку та виконав рефреш структури. Зверніть увагу, что таким чином виконується лише рефреш структури даних, але довідники у базі не заповнюються, як зробити це найпростішим засобом, дивиться ось тут - The simplest way to fill catalog in DB from VB.NET.
З іншого боку, якщо ми вже розмовляємо про ресурси, які зберігають схему даних, то у Assembly можливо вбудувати багато чого, наприклад ручками можна задати необхідні референси на DLL, навіть якщо їх не бачить лінкер (наприклад це цікаво для різноманітних динамічно підвантажуваних плагінів - Бизнес-обьекты с плагиної архитектурої.
2.4 Міграція (Package console/CMD utility/site code)
Ну а далі саме цікаве - як можна розгорнути сайт у будь-яку SQL-базу EF Migrations Command Reference. Це й є реальна перевага EF перед Linq-To-SQL (наприклад). Хоча, зробити такий самий функціонал у Linq-to-SQL (якщо ви маєте провайдери до різних DB Engine) можна самому за п'ять хвилин. Але подивимося що саме зробили мікрософтовські індуси у EF і чи реально можливо цим користуватися.
Вони пропонують нам зробити спеціфічний клас Configuration та в ньому зробити метод SEED, у якому зробити ініціалізацію даних.
Все це принципово можливо, але в мене це спрацювало лише один раз за всю мою історію користування EF. Справа тут в фантастично низької якості мікрософтовського софта. У 99% випадків я лише отримував стандартне індуське попередження "The parameter is incorrect. (Exception from HRESULT: 0x80070057 (E_INVALIDARG))". А от який саме параметр - догадайся сам, якийсь параметр якоїсь програми! Тобто я спробував трасувати саму студію, що я тільки не робив, але зрозуміти, який саме параметр не подобається мікрософтовським індусам, я так і не зрозумів.
Принципово ту ж саму міграцію можливо виконати безпосередньо у командній стрічці, це мабуть й краще, ніж у студії яка утворює ще більше помилок, ніж проста утілітка, але у мене вже не вистачає сил на боротьбу з тупими мікрософтовськими свинями.
Тому пропоную класичний засіб - ми просто виконуємо сформований SQL. Та потім заповнюємо базу даними без усяких індусів ровно у одну стрічку коду.
Принципово, якщо б міграція спрацювала, то ми в отримали замість простого SQL-кода, код Бейсіка, який утворює табли по CreateTable.
2.5 Публікація проекту з EF
Далі є пара цікавих питань щодо розгортання проєкту у більш реальне середовище. Звичайно девелопмент на начальних кроках ведуть у LocalDB, тобто це специфічний обмежений SQL-сервер, який не вміє нормально працювати, тобто він не має імперсоналізації, тобто логінов, звичайно він працює з MDF-файлом, який знаходиться у папці проєкту. Розгортати проєкт можна трьома засобами.
- На специфічний мікрософтовський хостинг AZURE. Про це я розповідати не буду принципово, бо по-перше про це розповідають мікрософтовські боти, а по друге AZURE настільки дорогий сервіс, що на мою думку він не має жодного сенсу.
- На локальний SQL-сервер на тієї ж самої VM, де розгорнутий WEB-сервер АБО на окремий SQL-сервер. Взагалі це величезне питання, що краще, окремий сервер, або SQL-Сервер на тієї ж самої машині, де й Web-сервер. Я займався цім питанням Питання про розподіл ресурсів у VmWare і здається, що у випадку VmWare більш ефективно об'єднувати SQL-server з Web-сервером. Але з ви не обов'язково можете працювати саме з MS SQL та не обов'язково з VmWare - і інших випадках класичний розділ проєкту на дві машини буде більш ефективним.
- Якщо ви вирішили викладати на SQL-сервер на тієї ж машини де у вас знаходиться WEB-сервер, то вам достатньо перекласти базу з MDF-файла LocalDB-сервера у повноцінний SQL-сервер ось так. Це скріни з цього мого проекту My project for refactoring huge database to prepare using it in Entity Framework.
- Якщо ви вирішили розгортати на SQL-сервер на іншій машині, то тут можуть бути проблеми, особливо якщо EDMX-файл винесений в окремий ClassLibrary-проєкт, а користуватися ним ви будете у іншому проекті. Це звичайні проблеми, наприклад у цьому проєкті - Проєкт Шаровоз була така ситуація. Я зробив там ось такий патчик для роботи WebMoney-шлюза для роботи сайта з іншим SQL-сервером, який означений у проекті, у якому визначений EDMX.
2.6 Профайлер трансляции EF з Linq у SQL та EF Retry Policy (повний код проєкту)
Ще одна важлива опція EF, це можливість зробити трасіровку усіх реквестів до бази, тобто уникнути запуск стандартного профайлера, який нібито повинен бути у будь якому DB Engine, але зрозуміло, що це непогана можливість. Для цього потрібно створити ось такий код.
- ILogger.vb - загальний інтерфейс логерів, як налаштовуються конфігом стандартні логери у NET почитайте наприклад ось тутне будемо на цьому зупинятися.
- Logger1.vb - логер, який пише у вікно Immediate window Visual Studio та у стандартний .NET лог. Неважко зробити й інший логер, який буде зберігати протокол запитів до SQL-серверу наприклад у текстовий файл.
- InterceptorLogging.vb - EF Command Interceptor з таймером. Має три метода ScalarExecuted (запит формується з EF методами Linq First/FirstOrDefault/Single/SingleOrDefault та інш.), ReaderExecuted (запит формується з EF методами ForEach/ToLiat/Sum/Count та іншi.), NonQueryExecuting (можливо запит теж формується у якихось випадках).
- InterceptorTransientErrors.vb - Так звана RetryPolicy aбо ExetutionStrategy - тобто код повтору SQL-запитів у занадто напруженому та перевантаженому SQL-сервері, такому як MS AZURE, який просто занадто часто відмовляє клієнтському софту у запитах до SQL-серверу. При розгортанні сайту на мікросовтовському хостінгі без цього модуля сайт працювати просто не буде.
- EF_Config.vb - EF автоматично шукає класи, що зробленi як потомки класу DbConfiguration та виконує їх. Логери, RetryPolicy та подібні речі звичайно викликаються з цього класу. Цю поведінку неважко й змінити, для цього потрібно зробити свій власний атрибут, та дописати його перед власним класом, що наслідує DbContext, та задати в ньому ім'я наприклад окремої сборки з GAC, яка буде робити лог SQL-запросів по всім сайтам на Web-сервере.
Я зробив експортну версію цього проекту (тобто Extensebility template), який ви можете завантажити собі EF ModelFirst with Logging and Deploy.zip.
Отже, на наш мега-сайтік, як бачите чудово працює, і ви можете наглядно зрозуміти мету утворення EntityFramework - як транслятора LINQ-кода у SQL-запроси до бази.
2.7 Альтернативи мікрософтовському ModelFirst
Ще раз нагадую, що EF Model дизайнер з MS Visual Studio ніяких переваг не має перед усіма іншими Model-First дизайнерами, особливо перед тими, що пропонуються за гроші. Наприклад дизайнер DevArt розгортає моделі без будь-яких індуських запоморочек (які ми бачили вище), працює відразу з будь-якими відомими базами (ніяких інших індуських запоморчек типа - це стара версія MS SQL і ми її вже не підтримуємо, купіть у нас нову - там теж немає), на моделях працює звичайний Drag-and-Drop замість Add Association у мікрософтовських індусів, та навіть цей ModelFirst дизайнер відразу утворює в один клік увесь код MVC-проекту. Може утворювати відразу всі врапери Middle-Level'в звернення до бази через Teleric-Nibernate-EF-Linq-to-SQL, та один клік переходити від одного типа звернення до бази до іншого.
Нажаль безкоштовні версії цього ModelFirst дізайнера мають обмеження у 10 табличок. І нажаль не підтримують Бейсік, тільки Шарп. Тобто якщо ви вибрали цей ModelFirst Designer, то перетворити тупий машинний код Шарпа на більш приємну для погляда людино-подібну мову VB вам доведеться за допомогою конвертера http://converter.telerik.com/ - бо я завжди казав, що програми пишуться не для машин, а для людей. І якщо програма на VB зрозуміла для очей хоч на 1% більше, ніж програма на Шарпі - користуватися потрібно тільки VB, щоб там не рахували мікрософтовські індуси.
3. Code First
Контент другої частини я бачу достатньо ясно, ось тут початок:
- 3. Code First
- 3.1. Site with Project and without project (порівняння типів проєктів).
- 3.2. Стартовий MVC-project Contoso University in VB.
- 3.3. Attributes and Fluent API.
- 3.4 Перелік атрибутів Data Annotations.
- 3.5 Scaffold template and custom scaffold template.
- 3.6 Close look to controller code
- 3.7 Виготовлення власних Extension-хелперов
- 3.8 Store state in ViewState/ViewBag/ViewData/TempData
4. Code First from existing Database
Третя частина поки що лише марево, часу в мене напевне не вистачить.
<SITEMAP> <MVC> <ASP> <NET> <DATA> <KIOSK> <FLEX> <SQL> <NOTES> <LINUX> <MONO> <FREEWARE> <DOCS> <ENG> <CHAT ME> <ABOUT ME> < THANKS ME> |