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
// Ассоциации
// Базовый запрос
Есть ли жизнь с ORM или типовая архитектура CRUD приложения
Предметная модель
Анемичная предметная модель
• Генерируется с помощью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 тест, но выполняются ночью или
под отладчиком.Требуется БД.
Есть ли жизнь с ORM или типовая архитектура CRUD приложения
Выполнение отчёта
• Отчёт может формироваться какое-то время (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

PDF
М. Коробов "Машинное обучение на фронте и в тылу", DUMP-2014
PDF
Извлечение информации из веб-страниц - Михаил Коробов, PyCon RU 2014
PDF
2013-02-02 03 Голушко. Полнотекстовый поиск с Elasticsearch
PDF
Apache Lucene + Hibernate = Hibernate Search
PPT
CodeFest 2012. Нелюбин Д. — Neo4j — графовая база данных
ODP
Distributed erlang
PDF
Data Driven Gameplay in UE4
PDF
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...
М. Коробов "Машинное обучение на фронте и в тылу", DUMP-2014
Извлечение информации из веб-страниц - Михаил Коробов, PyCon RU 2014
2013-02-02 03 Голушко. Полнотекстовый поиск с Elasticsearch
Apache Lucene + Hibernate = Hibernate Search
CodeFest 2012. Нелюбин Д. — Neo4j — графовая база данных
Distributed erlang
Data Driven Gameplay in UE4
CodeFest 2013. Иванов В. — Уменьшение расхода оперативной памяти в Java-прило...

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

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

Есть ли жизнь с 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 // Ассоциации // Базовый запрос
  • 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 тест, но выполняются ночью или под отладчиком.Требуется БД.
  • 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

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