问题 如何从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;
}

8347
2018-02-10 22:28


起源

我正在做你正在做的事情 - (1)使用带有投影的getSQL(...)以便不执行查询,以及(2)替换'?'与绑定一个接一个。我个人不知道更好的解决方案。 - David Fleeman
如果querydsl可以构建完全物化的查询并支持模式前缀,那么它将是动态查询构建所需的完美工具。我仍然希望这里有一些我可能遗漏的东西。 - MickJ
它确实支持模式前缀 - 给我几分钟,我会发布一个答案如何做到这一点。 - David Fleeman


答案:


要启用架构打印,请使用以下模式

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);

9
2018-02-11 18:30



谢谢。 Literals现在可以在配置后使用setUseLiterals。但即使在使用MySQLTemplates.builder()。printSchema()。build()之后,架构表示法仍然没有显示出来。我使用的是3.3.1版。 - MickJ
如果将变量与模式元数据一起使用,则模式前缀有效,新的PathImpl <Object>(Object.class,表)没有,使用代码生成或RelationalPathBase - Timo Westkämper
谢谢Timo,请您详细说明使用代码生成和RelationalPathBase的意思。 - MickJ
我更新了我的答案。 - Timo Westkämper
@TimoWestkämper - 似乎我总是以艰难的方式做事:( - David Fleeman


使用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类中有一个错字或错误,但你应该能够让它工作。祝你好运!


0
2018-02-11 16:19



这意味着我必须为模式前缀子类化每个模板类才能工作。 - MickJ
@MickJ用我的方法,是的。诀窍是 setPrintSchema(true) 声明 - 如果你能弄清楚如何设置另一种方式的print schema标志,那么请告诉我!这可能是可能的! - David Fleeman