JPA criteriabuilder group by 1 - jpa

I'm trying to migrate my postgres native querys to use criteriabuilder instead.
What I want to achieve is:
select date_trunc('day',t.starttime) AS day, count(*) AS no_of_users from login_table t group by 1 order by 1
So far I I don't see how to build the group by 1 order by 1.
This is how far I've gotten:
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<RequestPerWeek> cq = cb.createQuery(RequestPerWeek.class);
Root<TLogin> from = cq.from(TLogin.class);
String date = "week";
Expression<Calendar> dateTrunc=cb.function("date_trunc",Calendar.class,cb.literal(date), from.get(TLogin_.starttime).as(Calendar.class));
cq.select(cb.construct(RequestPerWeek.class,cb.count(from),dateTrunc));
I've tried several groupby alternatives, but noone works like I want it to :-|
best regards,
hw

We are using spring data jpa in our project and if you use it, there is no need to write criteria query for simple queries, you can simply write the query directly on top of your method and get the result. This approach is 'Using named parameters'
For example,
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where u.firstname = :firstname or u.lastname = :lastname")
User findByLastnameOrFirstname(#Param("lastname") String lastname,
#Param("firstname") String firstname);
}
Below link is useful for anyone who is using spring data jpa, if you are writing criteria query take a look if you can get your result using named parameters approach. This is simple and you write very less code.
http://docs.spring.io/spring-data/data-jpa/docs/1.4.x/reference/htmlsingle/#jpa.named-parameters

Related

Trying to Write JPQL For Complex Postgres Query

I'm working on an Admin UI for an authorization server. One of the features is to display a list of who has logged in, and we are doing that by querying a database table where the currently issued refresh tokens are stored. A user can log in from multiple devices to the same application, generating multiple tokens. At the moment the requirements are NOT to break down this view by device, instead if a user has logged in at all, they are to be shown in the list. If we revoke access (one of the other requirements from this UI), then all devices will have their refresh tokens revoked.
Anyway, the main thing tripping me up is the query. I'm writing the query to pull back all the tokens for the specified user, but for each client only the most recent one is retrieved. ie, if there are 5 tokens for a given user/client combination, only the one with the most recent timestamp will be returned to the UI. I'm trying to do this entirely with JPQL in my SpringBoot/Hibernate backend, which is communicating with a Postgres database.
I can write this in SQL several different ways. Here are two forms of the query that return the same results:
select r1.*
from dev.refresh_tokens r1
join (
select r2.client_id, max(r2.timestamp) as timestamp
from dev.refresh_tokens r2
group by r2.client_id
) r3 on r1.client_id = r3.client_id and r1.timestamp = r3.timestamp
where r1.user_id = 1;
select r1.*
from dev.refresh_tokens r1
where r1.user_id = 1
and (r1.client_id, r1.timestamp) in (
select r2.client_id, max(r2.timestamp) as timestamp
from dev.refresh_tokens r2
group by r2.client_id
);
The reason I've figured out multiple ways to do the query is because I'm trying to also figure out how to translate it into JPQL. I avoid doing native queries in Hibernate as much as possible, instead relying on the DB-agnostic JPQL syntax. However, I just can't figure out how to translate this to JPQL.
I know native queries and/or putting filter logic into my Java code are both options. However, I'm hoping this is possible with a standard JPQL query.
You can use this:
select r1
from RefreshToken r1
where r1.user.id = 1
and r1.timestamp = (select max(r2.timestamp) from RefreshToken r2 where r2.user.id = r1.user.id);
Depending on your exact use case, I think this Blaze-Persistence Entity Views could come in handy here.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(User.class)
public interface UserDto {
#IdMapping
Long getId();
String getName();
#Limit(limit = "1", order = "timestamp DESC")
#Mapping("tokens")
RefreshTokenDto getLatestToken();
#EntityView(RefreshToken.class)
interface RefreshTokenDto {
#IdMapping
Long getId();
String getToken();
}
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserDto a = entityViewManager.find(entityManager, UserDto.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
It will use a lateral join query behind the scenes which is the most efficient on PostgreSQL:
select u1.id, u1.name, r1.id, r1.token
from dev.user u1
left join lateral (
select *
from dev.refresh_tokens r
where r.user_id = u1.id
order by r.timestamp desc
limit 1
) r1
where r1.user_id = 1

Spring Data Jpa #query behaviours

Can anybody please tell me #Query annotation will support DB independence query mechanism
Example:
public interface UserRepository extends JpaRepository<User, Long> {
#Query("select u from User u where u.firstname like %?1")
List<User> findByFirstnameEndsWith(String firstname);
}
if i write this query will it support all the DBs like Mysql,oracle, postgres.
i found something like this in spring data jpa reference document site that
#Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
here is this means if i write nativeQuery=true it will treat as native query and if don't writer it will behave like a spring data jpa specific query or how it will behave please clarify.
If you set the nativeQuery flag to true, the query is treated as native sql whose behaviour will depend on DB host.If you dont set nativeQuery=true, then it is treated as JPQL and the real query for DB is generated by JPA according to the DB host hence it is DB independent.

Spring JPA findByColumnNameLike not working

I have a method -> findByfileNameLike(fileName,1, pageable) and its declaration in a repository that extends JPA Repository is
#Query(value = QUERY)
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
#LogExecutionTime
Page<BatchDTO> findByfileNameLike(String
fileName,#Param("departmentId")Integer departmentId, Pageable pageable)
Query is Select new DTO(bdm.id.batch.status) from Table bdm where bdm.id.departmentId =:departmentId and bdm.id.batch.status <> 7";
I want to filter the query by the column fileName.I have read to give the method name as given according to the doc of spring data jpa.But its not working.
Where and how will i give the fileName to be filtered?Should it be first parameter in the method?
Once you specify a query using the annotation #Query, Spring data jpa will not automatically create a query for you based on the method name and it will rely on the query provided by using the annotation.
The method findByfileNameLike will not make any difference here as a query is provided explicitly. Hope that answers your question

Spring Data JPA - Get All Unique Values in Column

I have a project using Spring Data JPA that consumes data from a table full of addresses. One of the columns of this table is the city. I would like to get a distinct list of cities that are in the table i.e. SELECT DISTINCT city FROM address.
Is there a way to do this using Spring Data JPA?
This can be achieved using the #Query annotation as:
public interface AddressRepository extends CrudRepository<Address, Long> {
#Query("SELECT DISTINCT a.city FROM Address a")
List<String> findDistinctCity();
}
Then, a call to addressRepository.findDistinctCity() would return the distinct city names.
A sample application is available on Github for review. Run integration test as mvn clean test to verify the approach.
Manish's comment should probably be bumped up to an answer (which i'll try to capture here since it ultimately solved my problem...although projections didn't seem to work with select distinct). The selected answer works in spring-data-jpa, but fails in spring-data-rest. One possible workaround for the spring-data-rest scenario is to create a separate #RestController for the select distinct results
#RestController
public class AddressRepoAdditionals {
#Autowired
private AddressRepository repo;
#RequestMapping("/additional/address/distictCities")
public List<String> findDistinctCity() {
return repo.findDistinctCity();
}
}
perhaps there's a similar but more elegant variation based on #RepositoryRestController
You can use native query.
#Query(value = "SELECT DISTINCT column_name FROM table_name", nativeQuery = true)
List<Type> findDistinctColumnValues();

JPA criteria builder - in human readable language

I understand the advantages of using a JPA criteria builder above the Java Persistence Query Language.
Is there an easy way to explain how to build up this kind of queries?
I need a more human readable explanation to build up my queries, this to have a kind of intuitive approach to query my database.
Example:
SQL:
SELECT id,status,created_at from transactions where status='1'
and currency='USD' and appId='123' order by id
Critera Builder with MetaModel:
Map<SingularAttribute<Transaction, ?>, Object> params = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Tuple> cq = cb.createTupleQuery();
Root<Transaction> r = cq.from(Transaction.class);
Predicate p= cb.conjunction();
for (Map.Entry<SingularAttribute<Transaction, ?>, Object> param: params.entrySet())
p = cb.and(p, cb.equal(r.get(param.getKey()), param.getValue()));
cq.multiselect(r.get(Transaction_.id), r.get(Transaction_.status),
r.get(Transaction_.created_at))
.where(p)
.orderBy(cb.asc(r.get(Transaction_.id)));
List<Tuple> result = em.createQuery(cq).getResultList();
This example was based on another question:
Complex queries with JPA criteria builder
I don't think there's an more clean way to write that kind of query following the standards and not using an hand wrote JPQL query, anyway out of the standard the are many query builders like: query dsl or Torpedo query or Object Query that allow to write query in a more clean way if that can help :)
Criteria query have some advantages of JPQL, such as: type safety, write SQL querias based on Java Programming model and make it portable. The easiest way in which I understand this when I started to work with JPA is think in the main objects that you need to use and their features.
CriteriaBuilder: Any statement that can be done using SQL like functions, reserved works, operations, predicates are part of this class, so builder need to be used to create those and apply them to the criteriaQuery.
CriteriaQuery: Any statement to have as goal to create a formal SQL statement are here, think on this as the boilerplate of the query definition, it have from, select, where, group by and all the statements, so this is the query itself and must be use to determine what you are really looking for from the database.
Now think to do a query you always must to use a Root, this mean select what will be your main table in your query definitions, based on that and helping from CriteriaQuery and CriteriaBuilder objects you can redefine the search to be whatever you want.