Комментарии 30
Вы, случайно, не ActiveRecord изобрели?
Так скоро дойдут до моделек и QueryBuilder-ов 😄
Здравствуйте, ActiveRecord это ORM-подход.
В статье предлагается не-ORM подход и, цитата,
Query пишется на нативном языке базы (например, SQL)
поэтому, нет
вы придумали dapper из .net
Здравствуйте, args это аргументы query. Среди них класса "сущности", поэтому нет
Не очень понял последнее предложение.
В dapper можно использовать параметризированные запросы и анонимные типы. И это считается лучшей практикой, чем добавлять значения в строку.
У dapper есть возможность работать с динамической типизацией (dto не нужен при этом).
Еще есть dapper query builder. Это можно использовать в качестве построителя запроса.
и database/sql и/или sqlc для go
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