Как получить полностью материализованный запрос из 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 выше, но вы должны быть в состоянии заставить его работать. Удачи!

Другие вопросы по тегам