Как получить полностью материализованный запрос из 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;
}
2 ответа
Чтобы включить печать схемы, используйте следующий шаблон
SQLTemplates templates = MySQLTemplates.builder()
.printSchema()
.build();
Подклассы SQLTemplates использовались ранее, но с некоторых пор шаблон компоновщика является официальным способом настройки шаблонов http://www.querydsl.com/static/querydsl/3.3.1/reference/html/ch02s03.html
И чтобы включить прямую сериализацию использования литералов
//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);
При работе с 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 выше, но вы должны быть в состоянии заставить его работать. Удачи!