Как получить полностью материализованный запрос из querydsl
Я пытаюсь использовать querydsl для создания динамических запросов для динамических схем. Я пытаюсь получить только запрос вместо того, чтобы фактически выполнить его.
До сих пор я столкнулся с двумя проблемами:
- Обозначение schema.table отсутствует. Вместо этого я получаю только имя таблицы.
- Мне удалось получить запрос, но он отделяет переменные и помещает '?' вместо этого это понятно. Но мне интересно, есть ли способ получить полностью материализованный запрос, включая параметры.
Вот моя текущая попытка и результат (я использую MySQLTemplates для создания конфигурации):
private SQLTemplates templates = new MySQLTemplates();
private Configuration configuration = new Configuration(templates);
String table = "sometable"
Path<Object> userPath = new PathImpl<Object>(Object.class, table);
StringPath usernamePath = Expressions.stringPath(userPath, "username");
NumberPath<Long> idPath = Expressions.numberPath(Long.class, userPath, "id");
SQLQuery sqlQuery = new SQLQuery(connection, configuration)
.from(userPath).where(idPath.eq(1l)).limit(10);
String query = sqlQuery.getSQL(usernamePath).getSQL();
return query;
И я получаю:
select sometable.username
from sometable
where sometable.id = ?
limit ?
То, что я хотел получить, было:
select sometable.username
from someschema.sometable
where sometable.id = ?
limit ?
Обновление: я придумал этот вид взлома, чтобы получить параметры, материализованные (не идеально и было бы лучше для лучшего решения). Но все же не смог получить нотацию Schema.Table.:
Взлом следует. Пожалуйста, предложите более чистый способ QueryDsl:
String query = cleanQuery(sqlQuery.getSQL(usernamePath));
private String cleanQuery(SQLBindings bindings){
String query = bindings.getSQL();
for (Object binding : bindings.getBindings()) {
query = query.replaceFirst("\\?", binding.toString());
}
return query;
}
Ответы
Ответ 1
Чтобы включить печать схемы, используйте следующий шаблон
SQLTemplates templates = MySQLTemplates.builder()
.printSchema()
.build();
Ранее использовались подклассы SQLTemplates, но с тех пор шаблон компоновщика является официальным способом настройки шаблонов http://www.querydsl.com/static/querydsl/3.3.1/reference/html/ch02s03.html#d0e904
И чтобы включить прямую сериализацию литералов, используйте
//configuration level
configuration.setUseLiterals(true);
//query level
configuration.setUseLiterals(true);
Вот полный пример
// configuration
SQLTemplates templates = MySQLTemplates.builder()
.printSchema()
.build();
Configuration configuration = new Configuration(templates);
// querying
SQLQuery sqlQuery = new SQLQuery(connection, configuration)
.from(userPath).where(idPath.eq(1l)).limit(10);
sqlQuery.setUseLiterals(true);
String query = sqlQuery.getSQL(usernamePath).getSQL();
Если вы всегда просто хотите получить строку запроса SQL, переместите setUseLiterals из запроса в конфигурацию.
Что касается использования выражений Querydsl, рекомендуется использовать генерацию кода, описанную здесь, http://www.querydsl.com/static/querydsl/3.3.1/reference/html/ch02s03.html
Это сделает ваш код типичным, компактным и читаемым.
Если вы хотите попробовать Querydsl без генерации кода, вы можете заменить
Path<Object> userPath = new PathImpl<Object>(Object.class, variable);
с
Path<Object> userPath = new RelationalPathBase<Object>(Object.class, variable, schema, table);
Ответ 2
При работе с QueryDSL вы должны предоставить шаблон для платформы базы данных для построения запроса. Я вижу, вы уже делаете это здесь:
private SQLTemplates templates = new MySQLTemplates();
private Configuration configuration = new Configuration(templates);
Чтобы имя схемы отображалось в сгенерированном запросе, единственным способом, который я нашел для этого, является (может быть, более простой способ) - расширить класс шаблона и явно вызвать this.setPrintSchema(true);
внутри конструктора. Вот класс, который должен работать на MySql:
import com.mysema.query.sql.MySQLTemplates;
public class NewMySqlTemplates extends MySQLTemplates {
public NewMySqlTemplates() {
super('\\', false);
}
public NewMySqlTemplates(boolean quote) {
super('\\', quote);
}
public NewMySqlTemplates(char escape, boolean quote) {
super(escape, quote);
this.setPrintSchema(true);
}
}
Затем просто используйте этот класс NewMySqlTemplates
вместо класса MySQLTemplates
следующим образом:
private SQLTemplates templates = new NewMySQLTemplates();
private Configuration configuration = new Configuration(templates);
У меня есть работа с использованием PostgresTemplates, поэтому у меня может быть опечатка или ошибка в классе NewMySqlTemplates выше, но вы должны иметь возможность заставить ее работать. Удачи!