While looking for java libraries to build queries in a database agnostic way I came across many including iciql, querydsl, jooq, joist, hibernate etc.
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.
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).
Can someone with experience in querydsl let me know if such a thing is possible with querydsl, and if yes, how.
If someone know of any other too which can satisfy my requirements, it would be really appreciated.
A very simple SQL query such as this:
@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));
}
Here is a small variation of ponzao's solution using PathBuilder
@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));
}
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:
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 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"...