SlideShare a Scribd company logo
Есть ли жизнь с ORM или
типовая архитектура
CRUD приложения
Велижанин Николай
Архитектура – самые важные решения
Типичное приложение с
типичными проблемами
Приложение
• Single Page App (SPA) with backend
• ~80% операций – Create, Read, Update, Delete (CRUD)
• Отчеты
• Database Driven Design
• Простая предметная логика
• Запросы в виде SQL внедрены в код
Проблемы
• Синхронизация схемы БД и кода приложения
• Что поменялось в БД?
• Изменения в схеме БД – какие SQL запросы это затронуло?
• Динамические структуры данных DataTable, Dictionary
• Схем объектов в коде нет. Определяются результатами SQL запросов
• Типы полей зависят от СУБД decimal если Oracle, double если MS SQL Server
• Поддержка нескольких СУБД
• Архитектурные решения не соблюдаются некоторыми
разработчиками
• Сложное развертывание / обновление
Может быть по-другому?
«Шаблон» приложения
• Успешно применен в 3 проектах
• Количество запросов на SQL стремится к нулю
За исключением пары-тройкиView и десятка хранимок
• Контроль соответствия кода и БД
• Переносимость блоков
Админка, справочники, отчёты, …
• Модифицируемость «шаблона» под текущие нужды без оглядки
на другие проекты
Если ORM, то какая?
Micro-ORMs: Dapper, PetaPoco
• Решают часть проблем
• Нет LINQ
• Нет генерации SQL
Heavy: Entity Framework
• Lazy Loading
• Миграции
• ChangeTracking
• Ассоциации Eager loading даже для коллекций
• LINQ
• Code first, Database first
Linq2DB
• Ассоциации Eager loading только для 1:1
• LINQ
• Bulk operations
• Оконные функции (Аналитические функции)
• Update и Delete с предикатом
• Custom’ные SQL функции и выражения в LINQ запросе
• Настраиваемые скриптыT4 для генерации модели на C#
• Расширяемость
• Отзывчивое сообщество на GitHub, быстро принимают pull request’ы
В чём сила, LINQ
• Запросы более предметные (ассоциации вместо join’ов)
• Запросы проверяются компилятором C#
• IntelliSense
• Легко производить рефакторинг, в том числе БД
• Проецирование
from q in query
from ls in db.PrRrlslayersortings.Where(ls => q.LclstrhistoryId == ls.LclstrhistoryId
&& q.Lsformation.LslayerId == ls.LslayerId).DefaultIfEmpty()
let f = new FormationInfo
{
КонсолидированноеГоловноеПредприятие = q.Lclstrhistory.Ddocompany.Parent.Shortname,
Предприятие = q.Lclstrhistory.Ddocompany.Shortname,
ПочтовыйАдрес = q.Lclstrhistory.Ddocompany.Mailingaddress,
ОКПО = q.Lclstrhistory.Ddocompany.Okpo,
ОКТМО = q.Lclstrhistory.Ddocompany.Oktmo,
ИНН = q.Lclstrhistory.Ddocompany.Inn,
КПП = q.Lclstrhistory.Ddocompany.Kpp,
…
НомерЛицензииИДатаРегистрации = q.License == null
? "лицензия не указана"
: $"{q.License.Series.Shortname}{q.License.No}{q.License.Kind.Shortname} от
{q.License.Begindate.ToShortDateString()}",
ЛицензионныйБлок = q.License == null
? "лицензия не указана"
: $"{q.License.Blockname} {q.License.Series.Shortname} {q.License.No}
{q.License.Kind.Shortname} {q.License.Begindate.ToShortDateString()}",
Лицензия = q.License == null
? "лицензия не указана“
: $"{q.License.Series.Shortname}{q.License.No}{q.License.Kind.Shortname}",
ГлубинаЗалеганияМин = q.Gasmindepth ?? q.Oilmindepth,
ГлубинаЗалеганияМакс = q.Gasmaxdepth ?? q.Oilmaxdepth,
// LEFT JOIN
// Ассоциации
// Базовый запрос
Предметная модель
Анемичная предметная модель
• Генерируется с помощьюT4 по существующей БД
• Практически не содержит логики. Допускается в partial классах
• Всегда соответствует актуальной схеме
• Тонкий типизированный слой абстракции над БД
• После перегенерации нерабочий код не собирается. Знаем что
править
Типичная сущность
Прикладной уровень
• В виде WEB API контроллеров
• Процедурный стиль
• ~95% - это запросы на LINQ
• Защищает предметную модель
Типичный подход: сущность – клиенту
• Провоцирует загрязнение предметной
модели внешними проблемами: UI,
сериализация.
• Поля «сбоку» для нужд одной формы
• Чувствительная или системная информация
• Лишние для конкретных сценариев поля
• Поменяли схему сущности – а в какихView
она используется? Где исправлять?
Модель
WEB API
Клиент (JavaScript)
Company
Запрос /
Company
DataTransfer Object (DTO)
• Для каждого сценария – свой DTO
• Содержит только требуемые поля
сущности
• Какие угодно дополнительные поля
• Может автоматически преобразовываться
в/из сущности. Включая ассоциации
• Может составляться из нескольких
сущностей
• Применение DTO обязательно для всего
WEB API
Модель
WEB API
Клиент (JavaScript)
Company
CompanyDTO
Запрос /
CompanyDTO
Запрос /
Company
Пример DTO
LocalStructLayer DTO
• Id
• Name
• Dome
• BeginStockTakingYear
• EndStockTakingYear
• …
• StratigraphicStageIds
• StratigraphicSystemName
• StratigraphicSystemSortOrder
• StratigraphicSeryName
• StratigraphicSerySortOrder
• …
LocalStructLayer
StratigraphicSeries
StratigraphicSystem
StratigraphicStage
1
:
1
1…1
• Id
• Name
• Dome
• BeginStockTakingYear
• EndStockTakingYear
• …
• Name
• SortOrder
• …
• Name
• SortOrder
• …
• Id
• Name
• SortOrder
• …
Система / Отдел / Ярус
Пласт локальных структур
Как гарантировать
обязательность DTO?
Задача: чтобы сделать неправильно было
невозможно
Обязательность DTO
• Проверка на уровне json сериализатора
AutoMapper как преобразователь DTO
Company
Company DTOAutoMapper
Configuration
Fluent Attribute based
LINQ Query Проецирование
AutoMapper
• [MapFromEntity]
• Convention-based matching или [MapFromProperty]
• Unit test для проверки, что все свойства в DTO успешно
преобразуются. config.AssertConfigurationIsValid()
Отчётность
Отчёты
• Разрабатываются с помощью LINQ
• Именование классов кириллицей
• На каждый отчёт обязательный интеграционный тест
• Наличие интеграционного теста проверяется Unit test’ом
• Интеграционный тест – xUnit тест, но выполняются ночью или
под отладчиком.Требуется БД.
Выполнение отчёта
• Отчёт может формироваться какое-то время (1-2 минуты)
• Формируем через персистентную очередь
• Для простого приложения, разрабатываемого одной командой,
достаточно Hangfire. Поддерживает MS SQL Server, Redis
Конфигурация
Типичный подход к конфигурации
• Настройки в web.config, app.config
• Разработчик иногда меняет web/app.config
• assemblyBinding, DbProviderFactories, logging, …
• При обновлении на сервере приходится мержить (пропускать,
перезаписывать?) app/web.config
• В тяжелых случаях конфиги разбросаны по разным местам
Конфигурация. Наш подход
• Web/app.config = бинарники
• Все, что настраивается, в отдельном файле. Лучше в одном.
• В одном месте: App_Data/Cfg, bin/../Cfg
Где используется?
• OIS Запасы и ресурсы: Новая классификация запасов
• OIS ППР РБ: ИС Поддержки и принятия решений по развитию
ресурсной базы
• OISТехнолог
• OIS Ремонты
Спасибо!
• Вопросы?

More Related Content

Similar to Есть ли жизнь с ORM или типовая архитектура CRUD приложения

SQL. Django, начало
SQL. Django, началоSQL. Django, начало
SQL. Django, началоpelid
 
Coding like a sex
Coding like a sexCoding like a sex
Coding like a sex
Max Arshinov
 
Корпоративное приложение на Rails
Корпоративное приложение на RailsКорпоративное приложение на Rails
Корпоративное приложение на Rails
Andrei Kaleshka
 
Class queries
Class queriesClass queries
Class queries
Eduard Lebediuk
 
разработка бизнес приложений (8)
разработка бизнес приложений (8)разработка бизнес приложений (8)
разработка бизнес приложений (8)
Alexander Gornik
 
Создание повторно используемых бизнес моделей с помощью технологии Domain Com...
Создание повторно используемых бизнес моделей с помощью технологии Domain Com...Создание повторно используемых бизнес моделей с помощью технологии Domain Com...
Создание повторно используемых бизнес моделей с помощью технологии Domain Com...
GetDev.NET
 
Обзор перспективных баз данных для highload / Юрий Насретдинов
Обзор перспективных баз данных для highload / Юрий НасретдиновОбзор перспективных баз данных для highload / Юрий Насретдинов
Обзор перспективных баз данных для highload / Юрий Насретдинов
Ontico
 
рентабельный код
рентабельный кодрентабельный код
рентабельный код
Max Arshinov
 
High Load 2009 Dimaa Rus Ready
High Load 2009 Dimaa Rus ReadyHigh Load 2009 Dimaa Rus Ready
High Load 2009 Dimaa Rus ReadyHighLoad2009
 
Моделирование для NoSQL БД
Моделирование для NoSQL БДМоделирование для NoSQL БД
Моделирование для NoSQL БД
Andrew Sovtsov
 
Node.js for enterprise 2021 - JavaScript Fwdays 3
Node.js for enterprise 2021 - JavaScript Fwdays 3Node.js for enterprise 2021 - JavaScript Fwdays 3
Node.js for enterprise 2021 - JavaScript Fwdays 3
Timur Shemsedinov
 
Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyRegn
 
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Yandex
 
django-and-postgresql
django-and-postgresqldjango-and-postgresql
django-and-postgresqlOleg Churkin
 
Юрий Буянов «Архитектура Goozy»
Юрий Буянов «Архитектура Goozy»Юрий Буянов «Архитектура Goozy»
Юрий Буянов «Архитектура Goozy»
e-Legion
 
YuryByyanov (e-legion) @ CodeCamp2011
YuryByyanov (e-legion) @ CodeCamp2011YuryByyanov (e-legion) @ CodeCamp2011
YuryByyanov (e-legion) @ CodeCamp2011CodeCamp
 
Clickhouse
ClickhouseClickhouse
Clickhouse
Clickky
 
ObjectManager, или как работать с большим количеством объектов на карте, Мари...
ObjectManager, или как работать с большим количеством объектов на карте, Мари...ObjectManager, или как работать с большим количеством объектов на карте, Мари...
ObjectManager, или как работать с большим количеством объектов на карте, Мари...
Ontico
 
кри 2014 elastic search рациональный подход к созданию собственной системы а...
кри 2014 elastic search  рациональный подход к созданию собственной системы а...кри 2014 elastic search  рациональный подход к созданию собственной системы а...
кри 2014 elastic search рациональный подход к созданию собственной системы а...
Vyacheslav Nikulin
 
Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs Reflection
Roslyn API: SyntaxTree vs CodeDom, SemanticModel vs ReflectionRoslyn API: SyntaxTree vs CodeDom, SemanticModel vs Reflection
Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs Reflection
Denis Tsvettsih
 

Similar to Есть ли жизнь с ORM или типовая архитектура CRUD приложения (20)

SQL. Django, начало
SQL. Django, началоSQL. Django, начало
SQL. Django, начало
 
Coding like a sex
Coding like a sexCoding like a sex
Coding like a sex
 
Корпоративное приложение на Rails
Корпоративное приложение на RailsКорпоративное приложение на Rails
Корпоративное приложение на Rails
 
Class queries
Class queriesClass queries
Class queries
 
разработка бизнес приложений (8)
разработка бизнес приложений (8)разработка бизнес приложений (8)
разработка бизнес приложений (8)
 
Создание повторно используемых бизнес моделей с помощью технологии Domain Com...
Создание повторно используемых бизнес моделей с помощью технологии Domain Com...Создание повторно используемых бизнес моделей с помощью технологии Domain Com...
Создание повторно используемых бизнес моделей с помощью технологии Domain Com...
 
Обзор перспективных баз данных для highload / Юрий Насретдинов
Обзор перспективных баз данных для highload / Юрий НасретдиновОбзор перспективных баз данных для highload / Юрий Насретдинов
Обзор перспективных баз данных для highload / Юрий Насретдинов
 
рентабельный код
рентабельный кодрентабельный код
рентабельный код
 
High Load 2009 Dimaa Rus Ready
High Load 2009 Dimaa Rus ReadyHigh Load 2009 Dimaa Rus Ready
High Load 2009 Dimaa Rus Ready
 
Моделирование для NoSQL БД
Моделирование для NoSQL БДМоделирование для NoSQL БД
Моделирование для NoSQL БД
 
Node.js for enterprise 2021 - JavaScript Fwdays 3
Node.js for enterprise 2021 - JavaScript Fwdays 3Node.js for enterprise 2021 - JavaScript Fwdays 3
Node.js for enterprise 2021 - JavaScript Fwdays 3
 
Система обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на GroovyСистема обработки бизнес-логики server-side приложения на Groovy
Система обработки бизнес-логики server-side приложения на Groovy
 
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
Подходы и технологии, используемые в разработке iOS-клиента Viber, Кирилл Лаш...
 
django-and-postgresql
django-and-postgresqldjango-and-postgresql
django-and-postgresql
 
Юрий Буянов «Архитектура Goozy»
Юрий Буянов «Архитектура Goozy»Юрий Буянов «Архитектура Goozy»
Юрий Буянов «Архитектура Goozy»
 
YuryByyanov (e-legion) @ CodeCamp2011
YuryByyanov (e-legion) @ CodeCamp2011YuryByyanov (e-legion) @ CodeCamp2011
YuryByyanov (e-legion) @ CodeCamp2011
 
Clickhouse
ClickhouseClickhouse
Clickhouse
 
ObjectManager, или как работать с большим количеством объектов на карте, Мари...
ObjectManager, или как работать с большим количеством объектов на карте, Мари...ObjectManager, или как работать с большим количеством объектов на карте, Мари...
ObjectManager, или как работать с большим количеством объектов на карте, Мари...
 
кри 2014 elastic search рациональный подход к созданию собственной системы а...
кри 2014 elastic search  рациональный подход к созданию собственной системы а...кри 2014 elastic search  рациональный подход к созданию собственной системы а...
кри 2014 elastic search рациональный подход к созданию собственной системы а...
 
Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs Reflection
Roslyn API: SyntaxTree vs CodeDom, SemanticModel vs ReflectionRoslyn API: SyntaxTree vs CodeDom, SemanticModel vs Reflection
Roslyn API : SyntaxTree vs CodeDom, SemanticModel vs Reflection
 

Есть ли жизнь с ORM или типовая архитектура CRUD приложения

  • 1. Есть ли жизнь с ORM или типовая архитектура CRUD приложения Велижанин Николай
  • 2. Архитектура – самые важные решения
  • 4. Приложение • Single Page App (SPA) with backend • ~80% операций – Create, Read, Update, Delete (CRUD) • Отчеты • Database Driven Design • Простая предметная логика • Запросы в виде SQL внедрены в код
  • 5. Проблемы • Синхронизация схемы БД и кода приложения • Что поменялось в БД? • Изменения в схеме БД – какие SQL запросы это затронуло? • Динамические структуры данных DataTable, Dictionary • Схем объектов в коде нет. Определяются результатами SQL запросов • Типы полей зависят от СУБД decimal если Oracle, double если MS SQL Server • Поддержка нескольких СУБД • Архитектурные решения не соблюдаются некоторыми разработчиками • Сложное развертывание / обновление
  • 7. «Шаблон» приложения • Успешно применен в 3 проектах • Количество запросов на SQL стремится к нулю За исключением пары-тройкиView и десятка хранимок • Контроль соответствия кода и БД • Переносимость блоков Админка, справочники, отчёты, … • Модифицируемость «шаблона» под текущие нужды без оглядки на другие проекты
  • 8. Если ORM, то какая?
  • 9. Micro-ORMs: Dapper, PetaPoco • Решают часть проблем • Нет LINQ • Нет генерации SQL
  • 10. Heavy: Entity Framework • Lazy Loading • Миграции • ChangeTracking • Ассоциации Eager loading даже для коллекций • LINQ • Code first, Database first
  • 11. Linq2DB • Ассоциации Eager loading только для 1:1 • LINQ • Bulk operations • Оконные функции (Аналитические функции) • Update и Delete с предикатом • Custom’ные SQL функции и выражения в LINQ запросе • Настраиваемые скриптыT4 для генерации модели на C# • Расширяемость • Отзывчивое сообщество на GitHub, быстро принимают pull request’ы
  • 12. В чём сила, LINQ • Запросы более предметные (ассоциации вместо join’ов) • Запросы проверяются компилятором C# • IntelliSense • Легко производить рефакторинг, в том числе БД • Проецирование
  • 13. from q in query from ls in db.PrRrlslayersortings.Where(ls => q.LclstrhistoryId == ls.LclstrhistoryId && q.Lsformation.LslayerId == ls.LslayerId).DefaultIfEmpty() let f = new FormationInfo { КонсолидированноеГоловноеПредприятие = q.Lclstrhistory.Ddocompany.Parent.Shortname, Предприятие = q.Lclstrhistory.Ddocompany.Shortname, ПочтовыйАдрес = q.Lclstrhistory.Ddocompany.Mailingaddress, ОКПО = q.Lclstrhistory.Ddocompany.Okpo, ОКТМО = q.Lclstrhistory.Ddocompany.Oktmo, ИНН = q.Lclstrhistory.Ddocompany.Inn, КПП = q.Lclstrhistory.Ddocompany.Kpp, … НомерЛицензииИДатаРегистрации = q.License == null ? "лицензия не указана" : $"{q.License.Series.Shortname}{q.License.No}{q.License.Kind.Shortname} от {q.License.Begindate.ToShortDateString()}", ЛицензионныйБлок = q.License == null ? "лицензия не указана" : $"{q.License.Blockname} {q.License.Series.Shortname} {q.License.No} {q.License.Kind.Shortname} {q.License.Begindate.ToShortDateString()}", Лицензия = q.License == null ? "лицензия не указана“ : $"{q.License.Series.Shortname}{q.License.No}{q.License.Kind.Shortname}", ГлубинаЗалеганияМин = q.Gasmindepth ?? q.Oilmindepth, ГлубинаЗалеганияМакс = q.Gasmaxdepth ?? q.Oilmaxdepth, // LEFT JOIN // Ассоциации // Базовый запрос
  • 14.
  • 16. Анемичная предметная модель • Генерируется с помощьюT4 по существующей БД • Практически не содержит логики. Допускается в partial классах • Всегда соответствует актуальной схеме • Тонкий типизированный слой абстракции над БД • После перегенерации нерабочий код не собирается. Знаем что править
  • 18. Прикладной уровень • В виде WEB API контроллеров • Процедурный стиль • ~95% - это запросы на LINQ • Защищает предметную модель
  • 19. Типичный подход: сущность – клиенту • Провоцирует загрязнение предметной модели внешними проблемами: UI, сериализация. • Поля «сбоку» для нужд одной формы • Чувствительная или системная информация • Лишние для конкретных сценариев поля • Поменяли схему сущности – а в какихView она используется? Где исправлять? Модель WEB API Клиент (JavaScript) Company Запрос / Company
  • 20. DataTransfer Object (DTO) • Для каждого сценария – свой DTO • Содержит только требуемые поля сущности • Какие угодно дополнительные поля • Может автоматически преобразовываться в/из сущности. Включая ассоциации • Может составляться из нескольких сущностей • Применение DTO обязательно для всего WEB API Модель WEB API Клиент (JavaScript) Company CompanyDTO Запрос / CompanyDTO Запрос / Company
  • 22. LocalStructLayer DTO • Id • Name • Dome • BeginStockTakingYear • EndStockTakingYear • … • StratigraphicStageIds • StratigraphicSystemName • StratigraphicSystemSortOrder • StratigraphicSeryName • StratigraphicSerySortOrder • … LocalStructLayer StratigraphicSeries StratigraphicSystem StratigraphicStage 1 : 1 1…1 • Id • Name • Dome • BeginStockTakingYear • EndStockTakingYear • … • Name • SortOrder • … • Name • SortOrder • … • Id • Name • SortOrder • … Система / Отдел / Ярус Пласт локальных структур
  • 24. Задача: чтобы сделать неправильно было невозможно
  • 25. Обязательность DTO • Проверка на уровне json сериализатора
  • 26. AutoMapper как преобразователь DTO Company Company DTOAutoMapper Configuration Fluent Attribute based LINQ Query Проецирование
  • 27. AutoMapper • [MapFromEntity] • Convention-based matching или [MapFromProperty] • Unit test для проверки, что все свойства в DTO успешно преобразуются. config.AssertConfigurationIsValid()
  • 29. Отчёты • Разрабатываются с помощью LINQ • Именование классов кириллицей • На каждый отчёт обязательный интеграционный тест • Наличие интеграционного теста проверяется Unit test’ом • Интеграционный тест – xUnit тест, но выполняются ночью или под отладчиком.Требуется БД.
  • 30.
  • 31. Выполнение отчёта • Отчёт может формироваться какое-то время (1-2 минуты) • Формируем через персистентную очередь • Для простого приложения, разрабатываемого одной командой, достаточно Hangfire. Поддерживает MS SQL Server, Redis
  • 33. Типичный подход к конфигурации • Настройки в web.config, app.config • Разработчик иногда меняет web/app.config • assemblyBinding, DbProviderFactories, logging, … • При обновлении на сервере приходится мержить (пропускать, перезаписывать?) app/web.config • В тяжелых случаях конфиги разбросаны по разным местам
  • 34. Конфигурация. Наш подход • Web/app.config = бинарники • Все, что настраивается, в отдельном файле. Лучше в одном. • В одном месте: App_Data/Cfg, bin/../Cfg
  • 35. Где используется? • OIS Запасы и ресурсы: Новая классификация запасов • OIS ППР РБ: ИС Поддержки и принятия решений по развитию ресурсной базы • OISТехнолог • OIS Ремонты

Editor's Notes

  1. Linq2DB создавался автором для решения своих производственных задач, EF создавался для абстрактных клиентов.