Комментарии 15
Если сделаете ещё один шаг то сможете прийти к идее компонентов доступа к БД которые во времена Delphi/ Interbase активно испольщовались и позволяли использовать логику на уровне БД хранимые процедуры.
Как вариант борьбы с рассинхронизацией схемы и запросов в БД давно придумали views.
Которые позволяют адаптировать изменения под «старые» требования
Согласен с вашим ходом мысли. Как хранимые процедуры, так и View предоставляют возможность обеспечивать обратную совместимость запросов при миграции БД. На эту тему был интересный доклад от Макса Грамина на PGConf в этом году (https://pgconf.ru/talk/3033632).
Однако в обоих случаях остаётся открытым вопрос интеграции со стороны языка. Ни View, ни хранимые процедуры не дают статических проверок, интеграционного кода и тестов в языке программирования: это остаётся на плечах программиста.
Непонятно, чем model-first лучше чем code-first: определив типы и их отношения, мы как раз и описываем модель. В том же ef core есть куча точек расширений, в которых можно получить доступ к этой модели и сгенерировать на ее основе всё что угодно.
Спасибо за ссылку. Интересная статья. Ироничная подача - тоже класс!
Насколько я понял, вы предлагаете отказаться от дихотомии: DB-first/Code-first, - и ввести третье представление между БД и языками. Данное представление будет нейтральным как относительно языков, так и относительно БД. Ценность этой нейтральности ясна: гибкость и устойчивость этой модели к переходам как между языками, так и между БД. Но помимо ценности есть и цена: переход сложности задачи от 2х до 3х тел со всеми вытекающими.
На мой взгляд, предлагаемый вами подход корректен и более гибок, чем DB-First, но и сложнее. Когда гибкость в отношении выбора БД не является требованием к системе, эта сложность будет избыточной. Иными словами, какой подход выбирать, как всегда в инженерии, "зависит".
Не думаю, что сложнее. Этот подход похож на DB-First тем, что правится база данных и потом генерируется то, что вам там надо по схеме. Отличие только в одном. DB-First ломается на нескольких окружениях, когда есть локальная БД и всякие /dev/stage/prod. У каждой БД будет своя истина, а в model-first база данных подгоняется под модель механизмом синхронизации. Code-first решает эту же проблему путём выкладывания в спец. таблицу истории миграций и жёстким запретом на трогание БД руками. Что очень неудобно.
И кстати. Если вы генерите sql запросы по схеме, можете попробовать скооперировать с моим инструментом. Его задача - выдать вашему скрипту актуальное состояние схемы данных и для абсолютной гибкости подхода я и сделал скрипт на стороне пользователя тулзы.
DB-First ломается на нескольких окружениях, когда есть локальная БД и всякие /dev/stage/prod. У каждой БД будет своя истина, а в model-first база данных подгоняется под модель механизмом синхронизации. Code-first решает эту же проблему путём выкладывания в спец. таблицу истории миграций и жёстким запретом на трогание БД руками.
А как же инструменты миграции Flyway, Liquibase, Sqitch и тп? Там так же накатывание миграций автоматизируется за счёт спец-таблиц. Конкретно это вовсе не прерогатива code-first.
Если вы генерите sql запросы по схеме
Их пишет пользователь.
Когда я только начинал и увидел hibernate, думал, что лучше его не будет, но часто именно такая магия, абстракция, становится узким местом и болью, особенно, если БД это основа приложения.
На одном из проектов я познакомился с JOOQ, DSL для работы с базой данных и насколько же удобно и прозрачно все это, теперь я жесткий фатан JOOQ) Понятно, что если у вас маленький проект ORM упростит работу, но с ростом будет сложнее с ним работать
Спасибо за статью)
Спасибо! Да. jOOQ в том же лагере инструментов. Если интересно, в доках есть сравнение pGenie vs jOOQ.
А смотрели sqlc ? Goorm? Они тоже могут генерить
Про Gorm не скажу, это похоже не ниша SQL-First.
А sqlc - прямой конкурент.
Принципиальное отличие в том, что sqlc целится на разные БД, из-за чего вынужден приводить внутренние представления к пересечению множества их возможностей, отбрасывая особенности. Поэтому, например, он до сих пор не поддерживает композитные типы Postgres. pGenie сфокусирован на Postgres и уже поддерживает продвинутые типы, включая композиты, многомерные массивы, multirange.
Ещё большое отличие в подходе к анализу. pGenie опирается на сам Postgres, разворачивая временный контейнер, проигрывая в нём миграции и прогоняя каждый запрос с извлечением метаданных из информационных схем. Благодаря этому поддерживаются любые синтаксические ухищрения и запросы любой сложности. Версию Postgres пользователь может выбирать, добиваясь соответствия продовой среде. В sqlc самописный эмулятор, который породил бесконечный поток багов несоответствия поведению Postgres. В последнее время, насколько я понял, они от него из-за этого стали плавно уходить.
Подробное сравнение есть в документации.
У нас .net ef + hot chocolate graphql. И много sql вообще под капотом собирается. Например, фильтры для админок склеиваются с фильтрами для контроля доступа, сверху докидываются сортировки, и т.п. Понятно, что в этом случае контроль над sql вообще утерян, но нам вроде и не надо - для всяких табличек в админах особенно.
В твоем подходе какая-то композиция запросов предполагается? Или только средствами БД (вьюшки и т.п.)?
Если подразумевается динамическое построение запросов, то пока не предполагается.
В демо-проекте есть пример со статическим запросом, реализующим динамическую выборку фильтров, условий сортировки и выборки. Для примера, вот генерируемый из него код Java.
Вопрос немного из другого разреза разработки - а зачем вообще пытаться что-то рефлектить "из SQL", или "из языка"?
В чем проблема использовать БД как фронт использует бэк, делая запросы к хранимкам (если уж там есть сложная логика)? В таком случае при миграциях приложение вообще трогать не нужно будет, если старый вид данных, конечно, можно как-то получить. Достаточно изменить хранимку в БД - т.е. при bзменении БД вы остаетесь в парадигме лишь этой БД.
Что касается тестов - естественно, они внешние должны быть, тут ничего не сделать, но эндпоинты на хранимках избавляют от необходимости переделывать те тесты, которые уже были для них написаны, и нужно просто написать тесты только для нового или изменившегося функционала.
Вообще, использовать рефлекты при работы с БД - это очень заманчивая, но очень порочная практика, как и ORM, ИМХО. Это ускоряет старт, но жутко мешает потом в жизненном цикле. Обычные запросы и более понятны (не надо гадать, во что они там трансформируются промежуточным слоем) и легче могут быть оптимизированы или вообще заменены. Единственная проблема - смена БД. Но это крайне редкая проблема, можно сделать миграцию и ручками раз в 10 лет.
Ну, либо я не понял сути вопроса.

Мой 14-летний путь отказа от ORM: череда инсайтов, приведшая к созданию SQL-First кодогенератора для PostgreSQL