Pull to refresh

Comments 37

При наличии парсера запроса немного странным выглядит необходимость указания его типа (type = QT_SELECT). Его можно из запроса извлечь.


А также, не пробовали получить названия параметров методов, чтобы явно не писать в аннотации TargetFilter имена? Вроде это можно.

>Его можно из запроса извлечь

В общем случае — нельзя. Хранимая процедура может возвращать результат как select, а может и нет. Узнать вы это можете — но только при выполнении.

Ну, для общего случая можно оставить параметр, а в частных случаях вполне можно автоматом выводить. Потом, думаю, для вызова хранимой процедуры в любом случае будет свой собственный тип, так что и этот случай наверняка можно автоматом опознать.

Не, ну в принципе в метаданных процедуры скорее всего есть все что нужно, я это просто к тому, что это а) это не слишком просто, б) не является частью стандарта SQL-92, и в) все это можно узнать только у базы, путем выполнения запроса. То есть просто парсер тут ничего не даст, по внешнему виду вызова процедуры ничего не видно.
А также, не пробовали получить названия параметров методов, чтобы явно не писать в аннотации TargetFilter имена

В семерке, не знаю как в 8-9, есть такой аттрибут (речь про формат .class) MethodParameters в котором есть часть, отвечающая за имя параметра:
MethodParameters_attribute {
       u2 attribute_name_index;
       u4 attribute_length;
       u1 parameters_count;
       {   u2 name_index;
           u2 access_flags;
       } parameters[parameters_count];
   }

name_index — это индекс указывает на значение в ConstantPool, где храниться имя параметра, но в описании этого элемента имеем:
The value of the name_index item must either be zero or a valid index into
the constant_pool table.
На своем опыте скажу, что частенько встречал 0, вместо реально-ожидаемых значений. Поэтому, отвечая на Ваш 2ой вопрос, скажу НЕТ. Если же имеется альтернативный способ извлечения, подскажите, буду Вам признателен.

посмотрите как это делает Spring Data — они же тоже имена у Param из имён переменных могут брать

Просто Netbeans в некоторых случаях показывает нормальные имена у параметров, даже если исходного кода или документации к джарнику не предоставляется, следовательно, эта информация где-то в class-файле. С другой стороны, это он делает не всегда, значит, она необязательная.


Если вы по аннотациям генерируете код во время компиляции, то сделать точно можно. А если рефлексией балуетесь, то вот не всегда, выходит, можно будет.

Согласен и подумаю как справить. Сейчас это проблема связанна с тем, что выбор стратегии работы с типом SQL-запроса начинается задолго до непосредственного разбора самого запроса. промахнулся
>ограничить поддерживаемый набор SQL конструкций

А вы уверены, что не потеряете при этом всю расширенную функциональность конкретной реализации?
А вы уверены, что не потеряете при этом всю расширенную функциональность конкретной реализации?


Да нет конечно. Вы только гляньте на примерный обзор возможных конструкций в том или ином диалекте. Здесь и десятка людей не хватит, чтобы их все поддерживать. Здесь возможен на мой взгляд только компромисс и точечный выбор специфичных, но ЧАСТО используемых вещей, вроде постраничной разбивки, определенных форматов тип данных (даты, время). Возможно что-то еще. Но в целом, если придерживаться стандарта SQL-92, то думаю можно поддерживать оговоренную функциональность
Увы, в стандарт например не входит такая вещь, как merge. И при этом она еще и делается сильно по-разному у MS SQL и PostgreSQL, так, для примера.
очень похоже на mybatis. и кстати, т.н. «динамические фильтры» идут там из коробки.
Когда готовил статью, я погружался в парадигму того или иного существующего фреймворка, где-то, чтобы просто освежить память, с чем-то просто никогда не работал. Мне кажется, то, что Вы называете динамическими фильтрами в MyBatis суть Dynamic SQL и кодить там все же придется, но в xml. Из достоинств Dynamic SQL — достаточно неплохой язык выражений и допускает его быстрое расширение, если потребуется. Но ключевое слово здесь кодить. С похожестью, наверное я не соглашусь, он просто другой.
Мне кажется, то, что Вы называете динамическими фильтрами в MyBatis суть Dynamic SQL и кодить там все же придется, но в xml

Не понимаю, что в вашем представлении значит «кодить». Написание SQL к кодингу не относится?
Есть ещё один известный мне способ делать запросы с динамической подстановкой параметров — Sql Provider:
@InsertProvider(type=ContactMapperSqlProvider.class, method=ContactMapperSqlProvider.CREATE_CONTACT_QUERY_NAME)
Long createContact(Contact contact);
...
class ContactMapperSqlProvider{
        private static final String CREATE_CONTACT_QUERY_NAME = "createContact";

        public String createContact(Contact contact){
            return new SQL() {{
                INSERT_INTO("TUTORS");
                VALUES("name", "#{name}").VALUES("surname", "#{surname}").VALUES("patronymic", "#{patronymic}").VALUES("description", "#{description}")
                    .VALUES("user_id", "#{user.id}");
                if (contact.getBirthDate() != null)
                    VALUES("birthday", "#{birthday}");
            }}.toString();
        }
    }

Чем то похоже на Criteria API в JPA/Hibernate, но выглядит симпатичнее
Да в том то и дело
     if (contact.getBirthDate() != null) VALUES("birthday", "#{birthday}");
Под этим я и понимаю кодинг — именно наличие оператора if.
Разумеется, указывать сам параметр и его значение в том или ином виде при любом подходе придется, другое дело для того же батиса, кто им мешал сделать так:
     // как вариант N1
     VALUES("birthday", "#{birthday}?");
     // или так как другой вариант N2
     VALUES("birthday", "#{birthday or nothing}");
или еще, как-то, более декларативно, согласно их представлениям понятия краткости и лаконичности.
Самое главное, я ни в коем случае не пытаюсь приуменьшить значение батиса для эко системы java, не подумайте или какого-либо другого фреймворка. Более того, я даже очень рад, что нам с Вами есть что сравнивать и из чего выбирать
Как мне кажется, в данном случае явное лучше неявного, и вариант с if-ом будет более поддерживаемым.
Согласен, конструкция с if нагляднее. Краткость != удобство.

ORM-фреймворки, ORM-объекты, SQL-фреймворки, XML, ещё какая-то херь — ради формирования текста sql- запроса? Да на кой это нужно?

это все не для формирвания sql запроса а скорее для удобногго и корректного маппинга в объекты.
Лично я не против такой позиции. Но если высказали А, то нужно сказать и Б.
A — есть у Вас подготовленный String sql-запрос к БД на выборку данных.
Б — а что дальше?
А дальше у нас всё просто — создаём соединение, создаём Recordset, выполняем запрос, итоги запроса обрабатываем так, как того требует текущая задача, закрываем соединение, и во избежание утечек памяти присваиваем использованным для выгрузки объектам значение Nothing.
А у Вас как?
А дальше у нас всё просто — создаём соединение, создаём Recordset, выполняем запрос, итоги запроса обрабатываем так, как того требует текущая задача, закрываем соединение, и во избежание утечек памяти присваиваем использованным для выгрузки объектам значение Nothing.
А у Вас как?
Пишешь sql-запрос, скармливаешь его движку, вуа ля и получаешь то, что нужно. Разумеется, соединение достаешь из пула, отработал таск, кладешь обратно.
В мире .net как-то с этим проще… например https://github.com/linq2db/linq2db или https://github.com/StackExchange/Dapper/blob/master/Readme.md
Скажите, а чем Вам таки не угодил JDBI? Вы указали, что рассматривали его, а в Вашем решении предлагаете нечто до боли напоминающее его Sql Objects: https://jdbi.github.io/#_sql_objects

Собственно, мы активно используем в продакшене именно его, и большинство методов DAO действительно выглядят как методы без реализации с аннотациями, внутри которых описаны sql-запросы.
Про угодил, не угодил я ничего в разрезе JDBI не писал. Его подход, а точнее стиль программирования очень похож c рассматриваемым решением. Он отлично покроет такие операции как INSERT, UPDATE и DELETE. Но больше всего в проектах приходится возиться с операцией SELECT. И здесь прослеживается основная разница: JDBI пошел по пути SpringTemplate — RowMapper, ColumnMapper и все такое. RefOrms пошел по пути анализа SQL-запроса, для того, чтобы мепить, фильтровать и прочие.
Автору спасибо за статью, но должен обратить внимание на орфографические ошибки — «преступить», «походу», «Да в прочим» и т.п. И разные переводы одного понятия — «меппинг — мэппинг».
А собственно я так и не понял, автор сам пишет такую библиотеку или показывает какую-то готовую?
Для своего использования или в публику тоже выйдет?
Исходники открыты на гитхабе, есть артефакт в мавен централ репозитории, не вижу каких-либо противопоказаний для использования желающими :) Другое дело, что его пилить нужно, батчинг, хранимые процедуры, генерация id для insert и так по-мелочи. Присоединяйтесь, коли будет желание, пару пул реквестов я уже заапрувил.
Интересно сравнение со Spring Data…
Вы забыли пласт фреймворков на базе EAV, который в сумме по объему рынка существенно обходит ORM.
Entity Attribute Value — аналог ORM, как и ORM является абстракцией над SQL.
Однако по своей механике довольно сильно отличается. Конечно же имеет как плюсы, так и минусы относительно ORM. Минусы относительно SQL у них схожи.
EAV есть основа платформ типа WP & Drupal. Которые сильно отличаются от MVC/ORM фреймворков, но при этом имеют примерно те же возможности, где то даже больше.
Сюда принимаем еще 2 факта:
— Грань между сайтом и веб приложением сегодня стерта
— Вслед за этим некогда простые CMS сумели эволюционировать в полноценные веб фреймворки

Однако они оставили за собой право лидеров рынка. Существенно обгоняя ORM подобные фреймворки как по доле рынка, так и по гибкости.

Я не против ORM, даже за в некоторых задачах. Также как за SQL в тех задачах где это уместно. Однако чаще всего я предпочитаю работать с EAV. Как и большинство участников мирового рынка если принимать во внимание доли реального использования и занимаемого объема рынка.

И тот факт что вы не учли сей тип фреймворков работы с данными — говорит о пробелах в данном материале.
Возможно стоит это восполнить.
Пробелы есть, скрывать не буду. Никогда не сталкивался в проде с таким решением.

Простите, из какого фреймворка из вышеперечисленных это: @TargetFilter?
И хотелось бы конечно сравнения, какие из них поддерживают эту и другие фичи..

@TargetFilter из RefOrms
Указание имени параметра фильтра в аннотации поддерживает JDBI, называется правда там это аннотация Bind.
Сравнение фреймворков это дело хорошее, но боюсь выходит за рамки этой статьи
Only those users with full accounts are able to leave comments. Log in, please.