如何从 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); 

若要使架构名称显示在生成的查询中,我发现执行此操作的唯一方法是(可能有更简单的方法)是扩展模板类并在构造函数内部显式调用。下面是一个应该适用于MySql的类:this.setPrintSchema(true);

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

}

然后只需使用此类来代替该类,如下所示:NewMySqlTemplatesMySQLTemplates

private SQLTemplates templates = new NewMySQLTemplates();
private Configuration configuration = new Configuration(templates); 

我使用PostgresTemplates进行这项工作,因此我在上面的NewMySqlTemplates类中可能有拼写错误或错误,但您应该能够使其正常工作。祝你好运!


推荐