如何在没有域类的querydsl中构造查询?

时间:2020-11-28 16:56:51

While looking for java libraries to build queries in a database agnostic way I came across many including iciql, querydsl, jooq, joist, hibernate etc.

在寻找java库以数据库不可知的方式构建查询时,我遇到了许多查询,包括iciql、querydsl、jooq、joist和hibernate等。

I wanted something that does not require configuration files and can work with dynamic schemas. For my application, I come to know about the database and the schema at runtime so I won't have any configuration files or domain classes for the schema.

我想要的东西不需要配置文件,可以使用动态模式。对于我的应用程序,我在运行时了解了数据库和模式,因此我不会为模式提供任何配置文件或域类。

This seems to be one of the core goals of querydsl but going through the documentation for querydsl I see a lot of examples for building dynamic queries using domain classes but I have not come across anything that explains how to build such database agnostic queries using just the dynamic information I have about the schema.

这似乎是querydsl的核心目标之一,但经历querydsl我看到很多的文档构建动态查询使用域类的例子,但我没有遇到任何解释了如何构建这样的数据库无关的查询仅使用动态信息的模式。

Jooq offers such functionality(See: http://www.jooq.org/doc/3.2/manual/getting-started/use-cases/jooq-as-a-standalone-sql-builder/) but have a restrictive license if I want to expand my focus to Oracle or MS SQL(Which I may not love but need to support).

Jooq提供了这样的功能(请参见:http://www.jooq.org/doc/3.2/manual/getting-started/use-cases/jooq-as- as- standard one- SQL -builder/),但是如果我想将关注点扩展到Oracle或MS SQL(我可能不喜欢,但需要支持),就需要有一个限制性的许可证。

Can someone with experience in querydsl let me know if such a thing is possible with querydsl, and if yes, how.

有querydsl经验的人能让我知道使用querydsl是否有可能实现这一点吗?

If someone know of any other too which can satisfy my requirements, it would be really appreciated.

如果有人知道还有什么可以满足我的要求,我将非常感激。

3 个解决方案

#1


3  

A very simple SQL query such as this:

一个非常简单的SQL查询:

@Transactional
public User findById(Long id) {
    return new SQLQuery(getConnection(), getConfiguration())
      .from(user)
      .where(user.id.eq(id))
      .singleResult(user);
}

...can be created dynamically like this (without any sugar added):

…可以像这样动态创建(不添加任何糖):

@Transactional
public User findById(Long id) {
    Path<Object> userPath = new PathImpl<Object>(Object.class, "user");
    NumberPath<Long> idPath = Expressions.numberPath(Long.class, userPath, "id");
    StringPath usernamePath = Expressions.stringPath(userPath, "username");
    Tuple tuple = new SQLQuery(getConnection(), getConfiguration())
      .from(userPath)
      .where(idPath.eq(id))
      .singleResult(idPath, usernamePath);
    return new User(tuple.get(idPath), tuple.get(usernamePath));
}

#2


3  

Here is a small variation of ponzao's solution using PathBuilder

这里是使用PathBuilder的ponzao解决方案的一个小变体。

@Transactional
public User findById(Long id) {        
    PathBuilder<Object> userPath = new PathBuilder<Object>(Object.class, "user");
    NumberPath<Long> idPath = userPath.getNumber("id", Long.class);
    StringPath usernamePath = userPath.getString("username");
    Tuple tuple = new SQLQuery(getConnection(), getConfiguration())
      .from(userPath)
      .where(idPath.eq(id))
      .singleResult(idPath, usernamePath);
    return new User(tuple.get(idPath), tuple.get(usernamePath));
}

#3


1  

Update: Timo has invalidated my original response by showing me how to do what I want WITHOUT having to replace the SQLQuery class. Here is his comment:

更新:Timo向我展示了如何在不需要替换SQLQuery类的情况下执行所需的操作,从而使最初的响应无效。这是他的评论:

query.getSQL(field1, field2, ... fieldN), getSQL is consistent with the
other methods which also take the projection arguments at last

I have removed my unnecessary class. Here is an example of using SQLQuery directly to get the SQL string WITHOUT executing the query (e.g., without using the list method):

我取消了不必要的课程。下面是一个使用SQLQuery直接获取SQL字符串而不执行查询的例子(例如,不使用list方法):

SQLQuery rquery = new SQLQuery(connection , dialect);

// Use getSQL with projections
rquery.from(qtable)
    .where(qtable.qfield1.eq("somevalue"));

SQLBindings bindings = rquery.getSQL(qtable.qfield1, qtable.qfield2);

// Get the SQL string from the SQLBindings
System.out.println(bindings.getSql());

// Get the SQL parameters from the SQLBindings for the parameterized query
System.out.println(bindings.getBindings());

This response answers how to use QueryDSL to build out a complete SQL query without actually executing the query. It does not address your additional requirements about "dynamic schemas" and "without domain objects"...

这个响应回答了如何使用QueryDSL构建完整的SQL查询,而不实际执行查询。它没有满足您关于“动态模式”和“没有域对象”的附加需求……

#1


3  

A very simple SQL query such as this:

一个非常简单的SQL查询:

@Transactional
public User findById(Long id) {
    return new SQLQuery(getConnection(), getConfiguration())
      .from(user)
      .where(user.id.eq(id))
      .singleResult(user);
}

...can be created dynamically like this (without any sugar added):

…可以像这样动态创建(不添加任何糖):

@Transactional
public User findById(Long id) {
    Path<Object> userPath = new PathImpl<Object>(Object.class, "user");
    NumberPath<Long> idPath = Expressions.numberPath(Long.class, userPath, "id");
    StringPath usernamePath = Expressions.stringPath(userPath, "username");
    Tuple tuple = new SQLQuery(getConnection(), getConfiguration())
      .from(userPath)
      .where(idPath.eq(id))
      .singleResult(idPath, usernamePath);
    return new User(tuple.get(idPath), tuple.get(usernamePath));
}

#2


3  

Here is a small variation of ponzao's solution using PathBuilder

这里是使用PathBuilder的ponzao解决方案的一个小变体。

@Transactional
public User findById(Long id) {        
    PathBuilder<Object> userPath = new PathBuilder<Object>(Object.class, "user");
    NumberPath<Long> idPath = userPath.getNumber("id", Long.class);
    StringPath usernamePath = userPath.getString("username");
    Tuple tuple = new SQLQuery(getConnection(), getConfiguration())
      .from(userPath)
      .where(idPath.eq(id))
      .singleResult(idPath, usernamePath);
    return new User(tuple.get(idPath), tuple.get(usernamePath));
}

#3


1  

Update: Timo has invalidated my original response by showing me how to do what I want WITHOUT having to replace the SQLQuery class. Here is his comment:

更新:Timo向我展示了如何在不需要替换SQLQuery类的情况下执行所需的操作,从而使最初的响应无效。这是他的评论:

query.getSQL(field1, field2, ... fieldN), getSQL is consistent with the
other methods which also take the projection arguments at last

I have removed my unnecessary class. Here is an example of using SQLQuery directly to get the SQL string WITHOUT executing the query (e.g., without using the list method):

我取消了不必要的课程。下面是一个使用SQLQuery直接获取SQL字符串而不执行查询的例子(例如,不使用list方法):

SQLQuery rquery = new SQLQuery(connection , dialect);

// Use getSQL with projections
rquery.from(qtable)
    .where(qtable.qfield1.eq("somevalue"));

SQLBindings bindings = rquery.getSQL(qtable.qfield1, qtable.qfield2);

// Get the SQL string from the SQLBindings
System.out.println(bindings.getSql());

// Get the SQL parameters from the SQLBindings for the parameterized query
System.out.println(bindings.getBindings());

This response answers how to use QueryDSL to build out a complete SQL query without actually executing the query. It does not address your additional requirements about "dynamic schemas" and "without domain objects"...

这个响应回答了如何使用QueryDSL构建完整的SQL查询,而不实际执行查询。它没有满足您关于“动态模式”和“没有域对象”的附加需求……