Spring Data JPA with QueryDSL, Count issue with aggregate function - java

I am using Spring Data JPA with QueryDSL and trying to use Sum function in where condition, As i am using pagination so i have to get count first.
So i have java code like below :-
NumberPath<Double> path = entityPath.getNumber("qty", Double.class);
BooleanExpression exp = path.sum().loe(120);
JPQLQuery countQuery = from(stock).where(exp);
long count = countQuery.count();
its creating query like this :-
select count(stock0_.stock_id) as col_0_0_ from stock stock0_
where sum(stock0_.qty)>=120;
and i am getting Error Code: 1111. Invalid use of group function.
above query is not working in SQL as well because sum function cant be use with count in where condition. I have not idea how to deal with such problem when i have to get count first and then fetch the real data.
Can someone please help me out with what is JPA approach to deal with such issue.
Please don't suggested #Query annotation because i can not use it. Due to dynamic filtration requirement.

You are using aggregate functions (sum). Then you need having() instead where()
This example is a really large one. You only need to care about pagination and having elements.
If you got different predicates and a pageRequest object.
Page request example:
pageRequest = new PageRequest(
MI_PAGE,
LIMIT,
Sort.Direction.valueOf( ASC ),
ORDER_FIELD);
EntityQ represents a QueryDSL generated meta-entity.
Query example:
new JPAQuery(em).from(entityQ).where( entityQ.id.in(
new JPASubQuery()
.from(entity2Q).innerJoin(entity2Q.objEntityQ, entityQ)
.where(ENTITY, PREDICATE)
.groupBy(entity2Q.objEntityQ.id)
.having( Wildcard.count.goe(SIZE) )
.list(entity2Q.objEntityQ.id)
))
.offset(pageRequest.getOffset() )
.limit( pageRequest.getPageSize() )
.orderBy(ORDERS).list(entityQ);
EDIT 2 More specific for your example:
I usually have a persistence context in my custom repositories:
#PersistenceContext
EntityManager em
Then, you could create a simple JPAQuery:
new JPAQuery(em)
.from(YOUR_STOCK_QUERYDSL_ENTITY)
.groupBy(YOUR_STOCK_QUERYDSL_ENTITY.field_to_sum)
.having(YOUR_STOCK_QUERYDSL_ENTITY.field_to_sum.sum().as("alias")
.goe(100));

Related

fetching single column values in JPA

I want to get all the values from a particular column in JPA and store all values into a list. currently, I am using the below approach but I am getting records in something else format.can someone please help me out
Query q1 = factory.createNativeQuery("select * from booking_attendee where booking_id="+id);
List<String> em1=q1.getResultList();
return em1;
query otput
em=[[Ljava.lang.Object;#68606667, [Ljava.lang.Object;#2cd7f99a, [Ljava.lang.Object;#137a5a5, [Ljava.lang.Object;#a45cc1c, [Ljava.lang.Object;#61fdc06d, [Ljava.lang.Object;#72f5eee1, [Ljava.lang.Object;#4e536797]
If you want to create a native query for this, it is more about how to solve this in SQL. You do not say SELECT * which means all columns. You would have to say SELECT your_column_name to select only a specific column.
Query q1 = factory.createNativeQuery("SELECT your_column FROM booking_attendee");
List<String> em1 = q1.getResultList();
The WHERE clause could and should be defined with the parameter binding of JPA. There are several advantages concerning performance and SQL injection.
Named parameter binding is special to the persistence provider (e.g. Hibernate). The common way for JPA is using ? to let your code be portable to other providers.
Query q1 = factory.createNativeQuery("SELECT your_column FROM booking_attendee b WHERE b.booking_id = ?");
q1.setParameter(1, id);
List<String> em1 = q1.getResultList();
Native queries offer the possibilities to use original SQL. Like this, some features which are specific for your database could be used with this. Nevertheless, if you do not have very specific SQL code, you should also have a look in JPQL, the specific query language of JPA, and the JPA Criteria API which offers advantages when you want to refactor your code, shows errors during compile time and makes the dynamic creation of queries easier.

Is there a way to dynamically generate Spring Data Jpa queries?

I'm writing an app using Spring Boot, Spring Data. And I'm trying to implement a filtering feature based on different filter parameters.
Using Spring Data queries we can define quite complex logic, e.g.:
#Query("SELECT u FROM User u WHERE u.status = 1")
Collection<User> findAllActiveUsers();
But what if the number of where clauses, order, limit, number of different parameters are unknown till we make an actual filter request which can be quite complex.
Right now filter params are send in a json object which I parse and retrieve them and the result sql query can be something like this:
SELECT * FROM table
WHERE field1 != `value1` and (field1 != ` value2 `OR (field1 = `value3` AND filed2 < 3))
AND field2 != 99
Is it possible to generate dynamically complex queries with undefined (till the actual filter request, during runtime) number of params, where clauses and other stuff?
I use this active project RSQL for JPA
https://github.com/perplexhub/rsql-jpa-specification
Sometime back I wrote an article on Spring Data JPA Query with Dynamic Where Clause. In this example you can send a Where Clause and Map of parameters for that. You can make use of this and modify it a bit suit your needs.
I would suggest using Spring JPA Specification
ref : https://spring.io/blog/2011/04/26/advanced-spring-data-jpa-specifications-and-querydsl/
To build it in a type safe manner, you can use FluentJPA.

How to get the newest record for every user using spring data mongodb?

I am struggling with a mongo query. I need to find a collection of documents in single query. The collection should contain document with newest date (field createdAt) for every user in single query.
There is a test case in Spock to demonstrate what I am trying to acheive:
def 'should filter the newest location for every user'() {
given:
List locationsInDb = [
buildLocation(USERNAME_1, '2017-02-03T10:37:30.00Z'),
buildLocation(USERNAME_1, '2017-03-04T10:37:30.00Z'),
buildLocation(USERNAME_2, '2017-02-05T10:37:30.00Z'),
buildLocation(USERNAME_2, '2017-03-06T10:37:30.00Z')
]
insertToMongo(locationsInDb)
when:
List filteredLocations = locationRepository.findLastForEveryUser()
then:
filteredLocations == [locationsInDb.get(1), locationsInDb.get(3)]
}
I found that distinct methods are a part of 2.1.0.M1 version so they are not available yet.
I was also trying with #Query annotation but the documentation (link below) does not specify how to create a query like mine.
https://docs.spring.io/spring-data/data-document/docs/current/reference/html/#d0e3309
Thanks for your help.
There are no means to express the query you are looking for via a derived query in Spring Data, nor using the MongoDB native query operators. Distinct as well will not do the job as it just extracts distinct values of a single field into an array.
Please consider using an Aggregation. Spring Data specifics can be found in the reference documentation.

Get count of rows for a repository query before the actual call

I have a Repository class implementing PagingAndSortingRepository.
There is a method as below which returns paginated results.
#Query("SELECT dt FROM Data dt JOIN dt.categories dc WHERE dt.service in (:services) AND dc.id = :cid")
public List<Data> findForCategoryAndServices(#Param("cid")String cid, #Param("services")Set<Service> services, Pageable page);
I need a cumulative count of all the data which can help depict pagination at UI. Is there some method out of the box for this?
Or should I make an explicit count query for the above query which is but obvious?
Return a Page<Data> rather than a List<Data>, and Spring-data will execute the count query for you, by deriving it from the actual query.
If it can't, or if you have a better count query, you can specify it using the countQuery annotation parameter.

selecting maximum field of a column using query dsl predicate

Im new to query dsl.Im using Spring repositories to get the result set.And one case i have to get the maximum of a column and get the fields in to an entity.My predicate code is below.I get error once i run this code.
public static Predicate getMaximum(){
QUserDetails details = QUserDetails.userDetails;
return details.id.eq(details.id.max());
}
And this is how i fetch my resultset using spring jpa
public UserDetails findByCustomerId(Predicate predicate);
And this is the error i get:
org.springframework.data.mapping.PropertyReferenceException: No property find found for type com.example.entity.UserDetails.Can anyone help me acheive what i want here.
You have to define a QueryDslJpaRepository which adds implementation for QueryDslPredicateExecutor
http://docs.spring.io/spring-data/jpa/docs/1.5.0.M1/api/org/springframework/data/jpa/repository/support/QueryDslJpaRepository.html
You can see a tutorial here:
http://www.petrikainulainen.net/programming/spring-framework/spring-data-jpa-tutorial-part-eight-adding-functionality-to-a-repository/
From the QueryDSL email group, apparently what you have to do to select the max ID is this:
from(entity).singleResult(entity.id.max())
So it's
JPAQuery jpaQuery = new JPAQuery(entityManager);
QEntity qEntity = QEntity.entity;
Long maxId = query.from(qEntity).singleResult(qEntity.id.max());

Categories