I'm using JOOQ for half a year now and must say that it's quite superb :)
The problem I encountered is: I'm trying to generate plain SQL query containing order by clause with case ... when statements to achieve custom sorting order as described in this part of JOOQ tutorial.
However, when I'm using Field.sortAsc(Collection< T> sortList) method and passing Collection of Strings I get following order by clause in query:
order by
case `type`
when ? then ?
when ? then ?
when ? then ?
when ? then ?
when ? then ? end asc
Because I'm not using JOOQ for executing queries, I need to specify these values myself which is quite inconvenient.
Partial solution to this problem was to pass Collection of Param<String> values obtained from original values using DSL.inline(T) method. However, in that case placeholders still exist and order by clause in query looks like:
order by
case `type`
when 'type_a' then ?
when 'type_b' then ?
when 'type_c' then ?
when 'type_d' then ?
when null then ? end asc
Is this expected behaviour or this can be considered as bug and should be reported?
For now, I worked this problem around by using Field.sort(Map sortMap) method, passing Map<Param<String>, Param<Integer>> to it with incremented integer values. There is minor problem with this method as well, because it returns SortField instance which doesn't have methods like asc(), desc() or sort(SortOrder) so in order to sort with different orders this map should be regenerated.
Thanks in advance for any help!
In order to extract all bind values from a query, use Query.getBindValues(). The sort indirection values should be in there. See also the relevant section of the manual.
Note, it might be generally useful to generate "inline" sort indirection values instead of bind values to prevent this in the future. Execution-plan-wise, I don't think there will be any difference. I have registered Issue #3147 for this.
Related
I want to write a negation / negative query where I can filter out those sets, where size is zero, but I am unable to write a morphia query for that.
In mongodb :
db.getCollection('xyz').find({'ArrayField.0': {$exists: true}})
Above query works.
I want to manipulate this query and form a morphia query which can run on arrays/sets for this
query.and(
query.criteria("ArrayField.0").exists(),
query.criteria("ArrayField").notequals(null)
)
You were so close!
query.and(
query.criteria("ArrayField.0").exists(),
query.criteria("ArrayField").notEqual(null)
)
More generally, there's another approach that works more broadly:
query.and(
query.criteria("ArrayField.0").exists(),
query.criteria("ArrayField").not().Equal(null)
)
This approach should work for any operation.
I should point out the $equal operator from the mongo query language is equal() not equals(). equals() is the Java defined equality method defined on Object. The name is confusing to be sure and, thanks to autocomplete, I've stumbled on that myself. But it's far too late to change that method name and honestly I haven't thought of anything better to call it.
Is there any difference when using Spring Data JPA keywords between:
List<SomeEntity> findBySomeCondition();
and
List<SomeEntity> findAllBySomeCondition();
No, there is no difference between them, they will execute exactly the same query, the All part is ignored by Spring Data when deriving the query from the method name. The only important bit is the By keyword, anything following it is treated as a field name (with the exception of other keywords like OrderBy which incidentially can lead to some strange looking method names like findAllByOrderByIdAsc).
This means something like this is perfectly valid:
List<SomeEntity> findAnythingYouWantToPutHereBySomeCondition();
And will execute exactly the same SQL query as:
List<SomeEntity> findBySomeCondition();
or
List<SomeEntity> findAllBySomeCondition();
The documentation for the 2.3.6 release of Spring Data discusses this feature:
Any text between find (or other introducing keywords) and By is considered to be descriptive unless using one of the result-limiting keywords such as a Distinct to set a distinct flag on the query to be created or Top/First to limit query results.
The purpose of feature was explained in a blog post about the then-upcoming 2.0 release of Spring Data:
Spring Data’s method parsing uses prefix keywords like find, exists, count, and delete and a terminating By keyword. Everything you put in between find and By makes your method name more expressive and does not affect query derivation.
To illustrate the difference lets look at the two functions:
1. Set<Policy> findAllByRoleIn(Iterable<Role> role);
2. Set<Policy> findByRoleIn(Iterable<Role> role);
The query generated by 1st function:
1. select policy.id, policy.role from policy where (policy.role in (? , ? , ? , ?))
The query generated by 2nd function:
2. select policy.id, policy.role from policy where (policy.role in (? , ? , ? , ?))
Conclusion: Clearly, if we look at the queries generated by both functions. We can clearly see, there is no difference between the two function definitions, they execute exactly the same query.
one difference is that with findAllBy Hibernate filters (#Filters from org.hibernate.annotations) are applied and so a different sql.
Actually, the difference between findallBy and findby, is that :
findAllBy returns a Collection but
findBy returns Optional.
so it's preferable to write List findAllBy instead of writing List findBy (but it will work also :p).
and to write Optional findBy instead of Optional findAllBy.
check this doc https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#repositories.core-concepts
findBy method is used if we want to find by name or some other criteria like findByFirstName(String firstName);
findAll methods generally finds by providing specification
List<T> findAll(Specification<T> spec);
Please see docs below for more clarity:
http://docs.spring.io/spring-data/jpa/docs/1.4.3.RELEASE/reference/html/jpa.repositories.html
While building a query using Hibernate, I noticed something rather odd. If I use sequential named parameters for the ORDER BY clause, Hibernate throws a QuerySyntaxException (the colon prefix being an unexpected token):
createQuery("FROM MyEntity ORDER BY :orderProperty :orderDirection");
However, when this is done with a plain SQL query the query is created without a problem:
createSQLQuery("SELECT * FROM my_entity_table ORDER BY :orderProperty :orderDirection");
I know Hibernate is doing more String evaluation for the HQL query, which is probably why the SQL query is created without an error. I am just wondering why Hibernate would care that there are two sequential named parameters.
This isn't a huge issue since it is simple to work around (can just append the asc or desc String value to the HQL instead of using a named paramater for it), but it struck my curiosity why Hibernate is preventing it (perhaps simply because 99% of the time sequential named parameters like this result in invalid SQL/HQL).
I've been testing this in my local, and I can't get your desired outcome to work with HQL.
Here is quote from the post I linked:
You can't bind a column name as a parameter. Only a column value. This name has to be known when the execution plan is computed, before binding parameter values and executing the query. If you really want to have such a dynamic query, use the Criteria API, or some other way of dynamically creating a query.
Criteria API looks to be the more useful tool for your purposes.
Here is an example:
Criteria criteria = session.createCriteria(MyEntity.class);
if (orderDirection.equals("desc")) {
criteria.addOrder(Order.desc(orderProperty));
}
else {
criteria.addOrder(Order.asc(orderProperty));
}
According to the answer accepted in this question, you can only define parameters in WHERE and HAVING clauses.
The same answer also gives you some ways to have a workaround for your problem, however I will add one more way to do this:
Use the CASE - WHEN clause in your ORDER BY, this would work by the following way:
SELECT u FROM User u
ORDER BY
CASE WHEN '**someinputhere**' = :orderProperty
AND '**someotherinput**' = :orderDirection
THEN yourColumn asc
ELSE yourColumn desc END
Please, note that in this approach would required you to write all the possible inputs for ordering. Not really beautiful but really useful, especially because you would not need to write multiple queries with different orderings, plus with this approach you can use NamedQueries, which would be possible by writing the query dinamically using string concats.
Hope this can solve your problem, good luck!
We are looking to to conditionally add where clauses to a SQL where class
For example we have a DAO that has a method with say 10 params.
For each of those params we check if it is null, if not we add an AND to the where clause.
The "base" query is a hard coded string and we concat it with the ANDS.
I'm looking for ideas for a more elegent way of doing this.
We are using hibernate elsewhere in the app
You can use the Hibernate criteria API to dynamically build queries.
For simplicity you can use variable argument method and start a loop for array and check for not null and concat it. otherwise you can use the Hibernate criteria API.
The Hibernate Criteria might be what you want.
http://www.mkyong.com/hibernate/hibernate-criteria-examples/
http://www.dil.univ-mrs.fr/~massat/docs/hibernate-3.1/api/org/hibernate/Criteria.html
I would like to get objects via Hibernate from database with concrete order. This order is something like that:
as the first I would like to get objects with column titled for example first_column not null,
as the second I would like to get objects with column second_column not null,
as the last I would like to get objects which third_column is the id for another object/table, and this another object has a field with concrete value for example: "something".
I have created criteria in this way:
criteria.addOrder(Order.asc("firstColumn"));
criteria.addOrder(Order.asc("secondColumn"));
but how can I meet the last requirement?
With the restriction I can do something like that:
criteria.createAlias("thirdColumn", "t");
criteria.add(Restrictions.eq("t.field", "something"));
But I have to use order, not restriction with three separate Criteria results, because I am using also setFirstResult() and setMaxResults() of the Criteria to implement pagination in my frontend.
If you can write the statement in SQL then you can probably get away with the approach mentioned in this post which is to create a custom subclass of Order.
I think you can simply use the "." separator and write your code as follow
criteria.createAlias("thirdColumn", "t");
criteria.addOrder(Order.asc("t.field"));