Как получить полностью материализованный запрос из 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;
}

person MickJ    schedule 10.02.2014    source источник
comment
Я делаю то же самое, что и вы: (1) использую getSQL(...) с проекциями, чтобы не выполнять запрос, и (2) заменяю '?' с привязками по одному. Я лично не знаю лучшего решения.   -  person David Fleeman    schedule 11.02.2014
comment
Если querydsl может создавать полностью материализованный запрос и поддерживать префикс схемы, это будет идеальный инструмент, необходимый для построения динамических запросов. Я все еще надеюсь, что есть что-то, что мне, вероятно, не хватает на картинке здесь.   -  person MickJ    schedule 11.02.2014
comment
Он поддерживает префикс схемы - дайте мне несколько минут, и я отправлю ответ, как это сделать.   -  person David Fleeman    schedule 11.02.2014


Ответы (2)


Чтобы включить печать схемы, используйте следующий шаблон

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);
person Timo Westkämper    schedule 11.02.2014
comment
Спасибо. Литералы теперь работают после setUseLiterals в конфигурации. Но обозначение схемы по-прежнему не отображается даже после использования MySQLTemplates.builder().printSchema().build() . Я использую версию 3.3.1. - person MickJ; 11.02.2014
comment
Префикс схемы работает, если вы используете переменные с метаданными схемы, их нет для нового PathImpl‹Object›(Object.class, table), вместо этого используйте генерацию кода или RelationalPathBase - person Timo Westkämper; 11.02.2014
comment
Спасибо, Тимо, не могли бы вы уточнить, что вы подразумеваете под использованием генерации кода и RelationalPathBase. - person MickJ; 11.02.2014
comment
@TimoWestkämper - кажется, я всегда делаю что-то сложно :( - person David Fleeman; 12.02.2014
comment
@DavidFleeman Нет проблем. В следующий раз, когда вы напишете неуклюжий обходной путь Querydsl, свяжитесь с нами;) - person Timo Westkämper; 12.02.2014
comment
Большое спасибо. Это работает отлично. Всего одно небольшое замечание: вам не хватает параметра в вызове конструктора RelationalPathBase. Он имеет 4 параметра. - person MickJ; 12.02.2014
comment
@MickJ Только что исправил параметры. - person Timo Westkämper; 12.02.2014

При работе с 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 выше, но вы сможете заставить его работать. Удачи!

person David Fleeman    schedule 11.02.2014
comment
Это означает, что я должен создать подкласс каждого класса шаблона, чтобы префикс схемы работал. - person MickJ; 11.02.2014
comment
@MickJ С моим подходом да. Хитрость заключается в операторе setPrintSchema(true) — если вы можете понять, как установить флаг схемы печати другим способом, пожалуйста, дайте мне знать! Наверное, это возможно! - person David Fleeman; 11.02.2014