HQL Query inside spring #Query annotation - java

I have been trying to understand the difference between HQL and JPQL. The hibernate documentation at here
suggest that writing select is necessary for JPQL but not in HQL. But when I try writing HQL or JPQL inside Query annotation of spring data JPA , both HQL and JPQL works .
import java.util.List;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
public interface UserRepository extends CrudRepository<User, Long> {
#Query(value = "from com.demo.spring.data.jpa.User u")
public List<User> findAllUsersHQL();
#Query(value = "select u from com.demo.spring.data.jpa.User u")
public List<User> findAllUsersJPQL();
}
My understanding is since the Query annotation is intended for JPA why is HQL supported ?
Or let me put in other words -
Can we write HQL in the Query annotation - Does spring data JPA supports both ?

I think it depends on which JPA impleemntation you use.
Even though Spring data says it supports JPQL, Spring data in itself isnt implememnting any functionality for validating and implementing queries with JPQL.
Spring will rely on underlying JPA impleemntation that will validate and convert given JPQL queries into plain SQL.
If the underlying adapter is a hibernate Adapter, There are fair chances that it will support HQL and will not limit the application to JPQL.
Moreover, as jdicker mentioned above, JPQL is a subset of HQL, or in the other words, hibernate provided mucm more functionalty than that of JPA.. so you shoudl be able to parse HQL in spring data as long as you are using Hibernate sa an underlying JPA engine.
DIY - You can try putting a breakpoint in QueryTranslatorImpl and confirm the behavior yourself.

Related

Can #Query annotation in Spring Data JPA take in a list of enums?

I've been trying to figure out how to take an input of a list of enums for my sql query. This is what it looks like:
#Query(value = "Select * from employees where city in :cities", nativeQuery = true)
List<Employee> findByCities(#Param("cities") List<City> cities);
I understand that for simple queries we can rely on the JPA Criteria API but I want to know if I can actually do it this way instead. Because if so, i can create more complicated queries (such as joins with another table) if I could have this flexibility of specifying the list.
Yes spring-data-jpa's #Query can take a list of enums.
This is my repository method
#Query("Select u from User u where u.userType in :types")
List<User> findByType(#Param("types") List<UserType> types);
This is my repository call
userRepository.findByType(Arrays.asList(AppConstant.UserType.PRINCIPLE)))
And this is the query logs
SELECT user0_.id AS id1_12_,
user0_.date_created AS date_created2_12_,
...
...
FROM users user0_
WHERE user0_.user_type IN ( ? )
Hope this helps.
PS: I tested this in my local machine with positive results.
Update 1
The same doesn't work with nativeQuery=true. I tested it on my local system and it doesn't seem to be working with native queries. However with JPQL it works fine as mentioned in the above answer.
May be this answer will help.

spring data compose #query query dynamically

I have situation in which I have to compose a JPQL query in some method, then pass this query to spring data query method to be used as the query in #Query annotation
#Query(value = ":DyanamicQuery")
List<PrizeInsuranceConfiguration> filterConfigurPrizeInsurance(String DyanamicQuery);
or at least the conditions part
#Query(value = "SELECT c FROM PrizeInsuranceConfiguration c WHERE :DyanamicConditions")
List<PrizeInsuranceConfiguration> filterConfigurPrizeInsurance(String DyanamicConditions);
Do, you can do that. There are two reasons why not:
sql injection (spring data work with prepared statements);
(result of first reasone) spring data create query tree and bind all params
But if you need dynamic query you can use Specifications, Query by Example or Querydsl.

Bulk update with HibernateTemplate and IN clause

I would like to perform a database bulk update using Spring's HibernateTemplate (Hibernate 5.1).
HibernateTemplate offers the following interface: public int bulkUpdate(String,Object...).
My query is UPDATE entity item SET item.attribute.id = ? WHERE item.id in (?.....?).
I had a lot of troubles and want to ask what is the proper way to use HibernateTemplate
The above query results in the deprecation warning [DEPRECATION] Encountered positional parameter near line 1, column 172 in HQ
Replacing the above query with JPA-style parameters (UPDATE entity item SET item.attribute.id = ?1 WHERE item.id in (?2,?3.....?N)) results in NullPointerException thrown by Hibernate when building parameter metadata
As seen on one of the most authoritative Hibernate sources, named parameters result in a misleading exception
Question is: how do I properly formulate a bulk update query using Spring's HibernateTemplate? As correctly reported by Mykong, HibernateTemplate automagically sets query parameters 0-based, but eventually the author got the program working with non-positional parameters without mentioning (or having at all) any warning.
I think that the recommended way to do that now a days is with Spring Data JPA. There is a getting started tutorial here.
So if you have an entity, you can add an interface that extends any of the reposiotry interfaces supported in SpringDataJpa and add a modifying query.
public interface CustomerRepository extends CrudRepository<Customer, Long> {
#Transactional
#Modifying
#Query("update Customer c set c.firstName = ?1 where c.id = ?2")
int updateNameById(String nameToUpdate, long id);
#Transactional
#Modifying
#Query("update Customer c set c.firstName = ?1 where c.id in (?2)")
int updateNameByIds(String nameToUpdate, List<Long> ids);
}
Then Spring will implement that method and you can use the it as:
customerRepo.updateNameByIds("newName", Arrays.asList(cust.getId()));
This will generate the following sql:
update customer set first_name=? where id in (?)
Here is the project I used to test with

Hibernate Criteria deprecation warrning after implementing Hibernate Search

For my web app I have to implement full text search - as I'm already using Hibernate with Spring Data JPA (on top of Spring Boot) I decided to implement Hibernate Search for full text Lucene queries. Everything works as expected but after implementing Hibernate Search I started to receive warnings:
Hibernate's legacy org.hibernate.Criteria API is deprecated; use the
JPA javax.persistence.criteria.CriteriaQuery instead
I don't use Criteria API for my Hibernate Search queries (as it is discouraged by Hibernate Search documentation anyway), my code for querying basically looks as follows:
import org.apache.lucene.search.Query;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.FullTextQuery;
import org.hibernate.search.jpa.Search;
import org.hibernate.search.query.dsl.BooleanJunction;
import org.hibernate.search.query.dsl.QueryBuilder;
...
#Override
#Transactional
public List<Picture> fullTextSearchByCriteria(List<SearchCriteria> criteria, String pageString) {
final FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
final QueryBuilder queryBuilder = fullTextEntityManager.getSearchFactory().buildQueryBuilder().forEntity(Picture.class).get();
final Query luceneQuery = buildFromCriteria(queryBuilder, criteria);
final FullTextQuery jpaQuery = fullTextEntityManager.createFullTextQuery(luceneQuery, Picture.class);
/* some fine tunning here with calls to .setFirstResult(), .setMaxResults() and
.getResultSize() for pagination. It's used for page wrapper that I omitted here for simplicity sake */
return jpaQuery.getResultList()
}
and buildFromCriteria(queryBuilder, criteria) is a method that builds boolean junction (also SearchCriteria class is just a regular POJO, nothing interesting there). This method looks as follows:
#Transactional
private Query buildFromCriteria(QueryBuilder queryBuilder, List<SearchCriteria> criteria) {
if (criteria == null)
return queryBuilder.all().createQuery();
BooleanJunction<BooleanJunction> junction = queryBuilder.bool();
for (SearchCriteria c : criteria) {
junction.must(
queryBuilder
.keyword()
.onField(c.getField())
.matching(c.getValue())
.createQuery()
);
}
return junction.createQuery();
}
Every use of this full text search results in Criteria API deprecation warning.
Does it use deprecated Criteria API under the hood? If so why Hibernate Search would use API that Hibernate deprecated? Actually I also got some deprecation warnings at application startup, when I call
FullTextEntityManager fullTextEntityManager = Search.getFullTextEntityManager(entityManager);
fullTextEntityManager.createIndexer().startAndWait();
for initial indexing.
Notes: I'm using Springs Specification in other part of app, that I would expect may use Criteria API under the hood, but I don't get deprecation warnings when using it and also didn't get any warning before Hibernate Search was added.
EntityManager is obtained via #PersistanceContext injection.
I would like to get rid of deprecated API usages if possible but I don't understand where Criteria API is used in this case and if it is even possible to change it to JPA CriteriaQuery (as I don't use it explicitly).
My dependencies with versions that I think might be important:
hibernate-core: 5.2.5.Final
hibernate-search-orm: 5.7.0.Beta2
Also using some extra dependencies for Analyzers:
solr-analysis-extras: 5.5.2
lucene-analyzers-stempel: 5.5.2
The conversion of Hibernate Search to the latest changes of Hibernate ORM is a complex work in progress.
You're hitting HSEARCH-2381.

Counting query in spring-data-couchbase (N1QL)

I'm writing couchbase repository using Spring module and I'm trying to add my own implementation of count method using N1QL query:
public interface MyRepository extends CouchbaseRepository<Entity, Long> {
#Query("SELECT count(*) FROM default")
long myCount();
}
But it doesn't work:
org.springframework.data.couchbase.core.CouchbaseQueryExecutionException: Unable to retrieve enough metadata for N1QL to entity mapping, have you selected _ID and _CAS?
So my question is: how can I write counting query using spring-data-couchbase?
I cannot find anything about this in spring documentation. link
This exception happens because the #Query annotation was designed with the use-case of retrieving entities in mind. Projections to a scalar like count are uncovered corner cases as of RC1. Maybe I can think of some way of adding support for it through explicit boolean flag in the annotation?
Unfortunately I was unable to find a workaround. I was trying to come up with a custom repository method implementation but it appears support for it is broken in 2.0.0-RC1 :(
edit:
The use case of simple return types like long, with a SELECT that only uses a single aggregation, should work so this is a bug/improvement. I've opened ticket DATACOUCH-187 in the Spring Data JIRA.
#Query("SELECT count(*) , META(default).id as _ID, META(default).cas as _CAS FROM default")
Change your query to this one.
Use this query :
#Query("SELECT count(*) as count FROM #{#n1ql.bucket} WHERE #{#n1ql.filter} ")
long myCount();

Categories

Resources