Вопрос поднимался не раз, но все же нигде нет исчерпывающего ответа, поэтому извините, пожалуйста.
Итак - КАКУЮ ORM выбрать для сложного многоуровневого проекта на ASP.NET MVC, в котором есть множество видов запросов - и сложные выборки с кучей join-ов, сложные запросы на обновление данных, вставка-удаление тысяч записей и т.п.
Дело в том, что проект мигрирует с php на asp.net и, как ни странно, в PHP + MySQL более десяти лет хватало голых запросов к базе плюс небольшой обертки для маппинга select-ов, несмотря на сложность запросов, в основном за счет существования конструкции "ON DUPLICATE KEY UPDATE".
В T_SQL такого нет. В предыдущей работе с приложениями Windows я пользовался классическим Dataset и этого хватало. Сейчас надо выбирать какую-то ORM, поддерживающую кеширование данных (как Local в EF), быстрый маппинг на голом SQL (как Dapper), bulk upsert (EF.Utilities / SQLBulkCopy).
Какого-то продукта, который сочетает полную функциональность для всех задач, я так и не нашел.
EF универсален, но сильно проигрывает по производительности в простых селектах, где нужен быстрый меппинг, в upsert (которого тупо нет, есть только отдельный insert/update либо AddOrUpdate, генерирующий ДВА запроса на каждый Entity), в сложности построения linq для сложных больших запросов (для сравнения, формирование raw-sql для кучи условий заняло примерно 70 строк с учетом форматирования, а конвертированный в Linqer запрос занял сотню строк и это без половины условий).
Dapper позволяет влегкую выбирать данные, используя сложнейшие raw-запросы, но не умеет работать с upsert.
EF.Utilities/SqlBulkCopy не встраиваются органично в EF, то есть для их использования нужно писать код отдельно, уходя от стандартного функционала EF.
Какие ORM существуют для решения всех вышеперечисленных задач комплексно? Может быть, есть некие гибридные связки (как EF + Dapper, о чем часто встречаются упоминания), кастомные решения в NuGet?
Хочется видеть DbContext, в котором реализована вся функциональность EF плюс туда же внедрен Dapper для работы с raw-запросами с возможностью внедрения полученных сущностей в DbContext DbSet-ы автоматом, с учетом отслеживания, плюс реализована функциональность bulk upsert БЕЗ дополнительных танцев с бубном (вызов SaveChanges и дальше ORM сама решает, какие данные на основе указанных ключей вставить, какие обновить, надо ли возвращать идентификаторы для отслеживания записей и т.п.).
Может быть, стоит уйти от MSSQL и работать в связке с MySQL, учитывая наличие конструкции "ON DUPLICATE KEY UPDATE"?
Может быть, стоит уйти от MSSQL и работать в связке с MySQL, учитывая наличие конструкции "ON DUPLICATE KEY UPDATE"?
Нечто аналогичное, есть и в Postgres. Если Вам нужна "мощная" БД - рекомендую посмотреть в её сторону, не зависимо программных платформ. Если просто БД общего назначения - то MySQL отличный выбор, по многим показателям.
Евгений Вольф: Вообще, конечно, переход на другую СУБД - это совсем крайний вариант, хотя бы с точки зрения практичности - искать хостинг проще со связкой IIS+MSSQL, чем с опциональным MySQL; мигрировать чей-то проект с MSSQL на свою площадку на другую СУБД дело уже совсем пипец какое неблагодарное.
я подразумевал какой-то "сложный" проект, который ставится минимум на VPS, а то и на выделенный сервер. Если у проекта нагрузка 100 человек в сутки, можно хоть SQLite использовать и извращаться над ним как угодно... Но, если речь идёт именно о "хостинге", то Вы безусловно правы.
Советую вам задуматься не только об ORM, но и об архитектуре вашего приложения.
ORM позволяет очень быстро реализовать слой ответственный за трансформацию моделей базы данных в обьекты бизнес модели. Фактически, он реализует кучу таких классических паттернов как Data Mapper, Identity Map, Lazy Load, Repository, Unit of Work и еще кучу всего. Все это вы получаете из коробки + такие приятные вещи для контроля версии базы данных как CodeFirst + migrations. Да, в отдельных случаях вы расплачиваетесь скорость чтения/записи.
Тут вам должна помочь правильная архитектура вашего приложения. Вы можете проектировать в соответсвии с принципами Domain-Driven-Design. В этом случае (в отличие от монолитного решения) приложения разделено на части. Каждая часть может иметь свою инфраструктуру, которая умеет записывать/читать данные из базы данных (repository pattern) и использовать какой то отдельный фреймворк. Части, которым не актуальна быстрая скорость, может легко использовать удобыный EF. Если в какой то части вы видите проблемы с быстродействием (bottleneck), вы можете изменить repository - выкинуть из нее EF и использовать Dapper. При правильной архитектуре, такая замена не затронет другие части системы и ваш рефакторинг пройдет безболезнено.
Я бы сначала сделал миграцию как таковую, а потом бы уже подбирал ORMы под те ли иные нужды. Единственно - желательно архитектурно работу с данными убрать в некий data access layer (чтобы потом можно было, покрыв тестами, править только его, не сильно трогая код выше уровнями). Миграцию в данном случае тогда делать лучше на голом ADO.NET так как он позволяет делать с базой все что вам надо всеми перечисленными способами.
Когда переедете с PHP можно будет заняться уже ORMами. Для CRUD операций нормально подойдет EF. Для bulk update/insert-ов - возможно проще оставить ADO.NET (такие операции я бы еще сделал асинхронными для обработки в бекграунде с последующей нотификацией об окончании - через опрос или через push уведомления - скажем WebRTC). Для выборок со сложными запросами - убрать эти сложные запросы в хранимые процедуры и дергать их либо через EF либо через ADO.NET. На счет маппинга данных на объекты используемые выше уровня data access - использовать AutoMapper. С его помощью можно смапить что-угодно на что угодно, главное не полениться и разобраться с возможностями его конфигурирования.
Единой ORM, которая хорошо охватит все перечисленные виды работы с данными и при этом будет оптимальной для всех, просто не может быть. У всех ORM в основе есть та или иная концепция - как надо работать с данными. Универсальные же системы - это когда все части работают одинаково (причем одинаково плохо обычно :) ).
По большому счету, наверное, я имел в виду какую-то реализацию репозиториев с возможностью максимального кеширования (в полуавтоматическом режиме) для фронтэнда и прямыми операциями с базой для тех частей, где происходит Create/update/Delete.
Пока что получается справляться методами EF + собственной несложной реализацией репозитория + EF.Plus.
Дмитрий Петров: для CRUD через EF обычно пишется с десяток хелпер методов (как extensions, например) - не так сложно. Задача разовая. Кеширование в MVC (если пользуетесь API) лучше делать пометив Controller actions методы атрибутами типа https://github.com/filipw/Strathweb.CacheOutput
Могу предложить взглянуть на Flexberry ORM. Он проектировался как раз для разработки сложных систем с длительным сроком сопровождения и доработок. Для полного цикла создания есть Фреймворк под ASP.NET (но, к сожалению только WebForms) или вариант связки OData + EmberJS.
Какие приемущества данного фреймворка перед EF, NHibernate? Выбирая непопулярный фреймворк вы сразу получаете ред недостатков: 1). маленькое community, малое количество инфомации в интернете, 2). В один прекрасный день его просто могут забросить. 3). Большинство разработчиков его не знают и не смогут поддерживать в будущем.