Comments 30
Вы, случайно, не ActiveRecord изобрели?
Query пишется на нативном языке базы (например, SQL)
В случае SQL - не просто на нативном языке, а на конкретном его диалекте, соответствующем используемой СУБД, а зачастую ещё и конкретной её версии.
Query проверяется на этапе компиляции, типы аргументов тоже
Угу... то-то регулярно попадаются вопросы типа "в штатном клиенте работает, а из программы нет". Для проверки нужно, чтобы в приложении работал полноценный парсер-валидатор, опять же учитывающий конкретную версию конкретной СУБД. К тому же некоторые СУБД используют "мягкую" систему типов.
Диалект и версия СУБД? А почему эта проблема должна перекладываться на бэк-разраба? Извините-подождите, вы решили поставлять свою новую, самую быструю и удобную СУБД - реализуйте пожалуйста драйвер по принятым стандартам SQL, чтобы у всех все работало.
вы решили поставлять свою новую, самую быструю и удобную СУБД - реализуйте пожалуйста драйвер по принятым стандартам SQL, чтобы у всех все работало
Так в рамках стандарта-то как раз у всех работает (да, бывают редкие отклонения, типа уникального NULL в SQL Server - но это всё же исключения, как правило исторически обоснованные). Фигня в том, что минимум половина, а обычно ещё больше, эффективных конструкций стандартом не покрывается и требует использования СУБД-специфичных кодовых конструкций.
А почему эта проблема должна перекладываться на бэк-разраба?
А вот не нужно экономить и валить всё и вся на одного разработчика. Пусть работает в тандеме с SQL-разработчиком.
Слава богу, я не один с такими мыслями...
Надоела эта куча промежуточных слоеностей их фреймворков, библиотек, паттернов.
Все программирование сводится к изучению нашлепок, а не самого ЯП и алгоритмов.
connection.fetch(query, args) -> result - норм тема, особенно если в query вызов хранимки, надо что-то похожее на универсальные хранимки до уровня БД, пока идея ждет своего героя.
Каждый раз когда я вижу нужно отказаться от ORM люди не понимают зачем они нужны. Они просто занесли их в проект потому что все так делают. Если ORM мешается вам на проекте перестаньте его использовать. Сила ORM проявляется только когда у вас 100500 CRUD есть с которыми вам надо работать. Плюс уменьшаются накладные расходы на DTO. Если же у вас этого всего нет зачем вы тащите в проект ORM?
Мне кажется, но в мире dotnet этих проблем уже нет. Хочешь быть поближе к базе, то есть dapper и linq2db. Хочешь удобств и функциональности, то есть ef core:
свой язык декларации схемы данных
Миграции ef core: один язык для разных СУБД. В идеале модели не меняются, для другой СУБД надо только сконфигурировать новый контекст.
свой язык запросов (Criteria Api, HQL, JPQL)
LINQ -- это лучше, чем учить t-sql, pl/sql и pgplsql. Но если очень хочется, то есть возможность выполнить raw sql.
свой оптимизатор (anti N+1)
Здесь от провайдера зависит, в текущих реализациях не сталкивался с такой проблемой.
свой pl/SQL - API вокруг Entity Manager, Sessions со скриптингом на Java
DbContext, DbSet, IQueryable, Expression -- вполне понятные стабильные api.
connection.fetch(query, args) -> result
Идея хорошая, но есть ряд проблем:
нужна поддержка на уровне языка, у шарпа есть source generators, а в мире java что?
где брать метаданные для вывода типов? что делать если sql динамический или СУБД не умеет отдавать эти данные?
Начнешь эти проблемы решать и сделаешь еще один орм, только с сырым sql :)
Exposed для kotlin очень хорошо подходит под ваши требования. Хоть и является почти ORM
В предложенной концепции, схема декларируется в SQL скриптах миграции. Все запросы пишутся "по месту", то есть с базы получаются нужные проекции в виде dto. Сами dto это рекорды или классы с final полями - никаких аннотаций на них нет. Поля dto инферятся автоматически, исходя из запросов. Все решение 100% typesafe
Концепция хорошая, но не новая :) В ef core есть scaffold, который по существующей базе сгенерирует dto и контекст бд, в linq2db есть шаблоны для генерации dto. Для проекций dto в linq изначально имеет анонимный тип, который при необходимости с помощью рефакторинга превращается в именованный тип. Не удивлюсь, если для hibernate и jooq можно также всё настроить.
Да, так и есть, однако если посмотреть на market share этих технологий, то мы увидим тотальное доминирование ORM. Значит, на это есть причины. И, как нам кажется, причины в деталях реализации. Кстати, можете рассказать что на практике значит "при необходимости с помощью рефакторинга превращается в именованный тип" ? Как выглядит такой рефакторинг?
Нам надо, чтобы имея dto - классы объектов, и таблицы базы данных, сохранять и доставать в/из базы одним вызовом. При этом dto не должно обременяться барахлом из ОРМ, то есть, детали реализации persistence не должны вылезать дальше слоя persistence. При этом dto и таблицы базы могут различаться, иногда весьма значительно (диктуются деталями реализации хранения в базе). Какая еще генерация?
Кроме того, надо реализовать множество срезов таблицы, когда в dto должно попадать только часть полей исходной таблицы (по требованиям производительности). А еще надо сохранять отдельные поля. Много и часто.
Хибернат при таких условиях - тяжкие гири, потому что приходится воротить классы entity, трансляцию dto в entity и обратно, сохранение отдельных полей в виде достать объект - изменить поле - сохранить объект.
Интерес представлял Spring Data JDBC. Вектор отличный. Но и он недостаточно хорош, потому что детали реализации persistence лезут в бизнес-слои в виде необходимости классы dto загрязнять @Entityи @FifthColumn
В связи с этим материал автора представляет большой интерес, но нужно больше информации. Как задается dto в persistence, где указывается соответствие полей dto полям таблиц? Для нас размещение такой информации в базе и генерация по ней кода неприемлемо, потому что необходимо менять слой persistence от базы к базе и даже к nosql, при этом требуется, чтобы слои бизнеса не менялись.
Да, возможно dto я зря употребил, читай как entity. Но в ef core entity можно описывать без атрибутов/аннотаций, вся конфигурация будет в DbContext. Про java не скажу, но не понятно, почему не рассматриваете jooq https://www.jooq.org/doc/latest/manual/sql-execution/fetching/pojos/.
Для нас размещение такой информации в базе и генерация по ней кода неприемлемо, потому что необходимо менять слой persistence от базы к базе и даже к nosql, при этом требуется, чтобы слои бизнеса не менялись.
Если у вас entity и dto сильно отличаются, то здесь без написания кода не обойтись.
Ну, для селектов это хорошо работает, да. Но орм-ы то и вводят свой уровень сложности для того, чтобы мочь не только селекты выполнять. (Но с мыслью, что это вторая субд по объему доки я очень согласен, разработчиками орм декларируется, что разработчику сложно изучить нативный уровень бд и пусть он лучше изучит «простой» орм, но реальность приводит к тому, что нужно экспертно владеть и базой и орм, чтобы мочь разбираться в возникающих проблемах).
Уйти от ORM