如何从querydsl获得完全物化的查询
Posted
技术标签:
【中文标题】如何从querydsl获得完全物化的查询【英文标题】:How to get fully materialized query from querydsl 【发布时间】:2014-03-08 11:50:40 【问题描述】:我正在尝试使用 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 ?
更新:我想出了这种 hack 来实现参数化(不理想,希望有更好的解决方案)但仍然 无法获得 Schema。表格符号起作用:
Hack 紧随其后。请建议更清洁的 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) 使用带有投影的 getSQL(...) 以便不执行查询,以及 (2) 替换“?”以一对一的方式绑定。我个人不知道更好的解决方案。 如果 querydsl 可以构建完全物化查询并支持模式前缀,它将是动态查询构建所需的完美工具。我仍然希望这里的图片中可能缺少一些东西。 它确实支持模式前缀 - 给我几分钟,我会发布一个答案如何做到这一点。 【参考方案1】:使用 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 类中可能有错字或错误,但您应该能够让它工作。祝你好运!
【讨论】:
这意味着我必须对每个模板类进行子类化才能使架构前缀工作。 @MickJ 用我的方法,是的。诀窍是setPrintSchema(true)
语句——如果你能弄清楚如何以另一种方式设置打印模式标志,那么请告诉我!有可能!【参考方案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);
【讨论】:
谢谢。文字现在在 setUseLiterals 配置之后工作。但是模式符号仍然没有出现,即使在使用 MySQLTemplates.builder().printSchema().build() 之后。我使用的是 3.3.1 版。 如果您使用带有模式元数据的变量,则模式前缀有效,新 PathImpl 谢谢 Timo,您能否详细说明一下使用代码生成和 RelationalPathBase 的含义。 @TimoWestkämper - 似乎我总是以艰难的方式做事:( @DavidFleeman 没问题。下次您编写笨重的 Querydsl 解决方法时,请联系;)以上是关于如何从querydsl获得完全物化的查询的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 QueryDSL 在查询中使用 SAMPLE 关键字
直接从querydsl更新数据时如何刷新Spring JPA?