join in spring data query repository - java

#Query("select u from User u join u.favoriteRestos s where u.id = ?1 ")
User findByIdWithFavoriteRestos (Long userId);
O have this query in the my repo, but instead of returning a User with empty favoriteRestos collection is returning a null user
that returns also a null user:
#Query("select u from User u join fetch u.favoriteRestos s where u.id = ?1 ")
User findByIdWithFavoriteRestos (Long userId);
I also tried with:
#Query("select u from User u left join u.favoriteRestos s where u.id = ?1 ")
User findByIdWithFavoriteRestos (Long userId);

It doesn't find any user, because join is an inner join. You need to add left keyword:
#Query("select u from User u left join fetch u.favoriteRestos s where u.id = ?1 ")
User findByIdWithFavoriteRestos (Long userId);
P.S.: fetch is also needed if you have a default (lazy) to-many mapping if you want to populate the collection.

Related

how to write inner join a selected table query in hibernate.ejb

I have a query working fine:
StringBuilder query = new StringBuilder(
"select o.deviceName, o.deviceOs, o.loginOn, e.username, e.name, e.idNo from LoginHistory o, User e ");
query.append(" where o.userId = e.userId");
Query q = getEm().createQuery(query.toString());
This createQuery() will go to createQuery() in class org.hibernate.ejb.AbstractEntityManagerImpl.
I want to edit the query to get the last login for each user. The following SQL query can run in a db2 command successfully:
select m1.*, m2.*
from tibs.LoginHistory m1 inner join (
select userId, max(loginOn) as loginOn from tibs.LoginHistory group by userId
) m2
on m1.userId = m2.userId and m1.loginOn = m2.loginOn;
But when I try to apply this in my code above, it will hit QuerySyntaxException: unexpected token: at ( after inner join.
Code is something like:
StringBuilder query = new StringBuilder(
"select o.deviceName, o.deviceOs, o.loginOn, e.username, e.name, e.cif, e.idNo from LoginHistory o, ECUser e ");
query.append("inner join (select o2.userId, o2.max(loginOn) as loginOn from LoginHistory group by userId) o2 ");
query.append("on o.userId = o2.userId and o.loginOn = o2.loginOn");
query.append(" where o.userId = e.userId");
Is this workable in this way? If yes, what syntax should I use?
Or does Hibernate not accept this, and I need to do it in another way?
Add on**
Even I change my query to this, still the same:
StringBuilder query = new StringBuilder(
"select o.deviceName, o.deviceOs, o.loginOn, e.username, e.name, e.cif, e.idNo from LoginHistory o, ECUser e ");
query.append("inner join (select o2.userId, o2.max(loginOn) as loginOn from LoginHistory o2 group by userId) ");
query.append("on o.userId = o2.userId and o.loginOn = o2.loginOn");
query.append(" where o.userId = e.userId");
I think the inner query should be as follows (note position of o2):
(select o2.userId, o2.max(loginOn) as loginOn from LoginHistory o2 group by userId)
Please name variables appropriately to facilitate comprehension.
It would be helpful if o2 was renamed to lh, since it represents LoginHistory entity.
(select lh.userId, lh.max(loginOn) as loginOn from LoginHistory lh group by userId)
You can use the following query:
select o.deviceName, o.deviceOs, o.loginOn, e.username, e.name, e.idNo
from LoginHistory o, User e
where o.id = (select max(lh.id) from LoginHistory lh where lh.userId = e.userId)

How can I translate a typed query into a criteria builder object?

I have the following code using TypedQuery, but due to some lack of dynamic functionality with ORDER BY, I would like to transform it into a criteria builder object. Is it possible to achieve the same query with the criteria builder?
TypedQuery<User> query = this.entityManager.createQuery("SELECT u FROM User u LEFT JOIN sales s ON u.id = s.user_id AND u.username LIKE :username", User.class);
query.setParameter("username", "%" + sampleUsername.toLowerCase() + "%");
Yes. Every JPQL query can be implemented with Criteria API

How select distinct value with pageable Spring data JPA?

I want to make a distinct select in my table with pagination, but it is claiming this error. Does anyone know how to solve it?
org.postgresql.util.PSQLException: ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
#Query(value = "SELECT DISTINCT budget.* FROM budget LEFT JOIN user_budget ON budget.id = user_budget.budget_id ORDER BY budget.created DESC, ?#{#pageable}",
countQuery = "SELECT DISTINCT count(*) FROM budget LEFT JOIN user_budget ON budget.id = user_budget.budget_id",
nativeQuery = true)
public Page<Budget> findAllByfilter(Pageable pageable);

Spring Data Native query pagination not working

I am using Spring Boot 2.0.2.RELEASE with Spring Data JPA. I am trying to do implement pagination with native query in MySql, my code is :
#Query(nativeQuery=true, value = "SELECT DISTINCT ud.latitude,ud.longitude,u.user_id userId FROM users u \n" +
"INNER JOIN user_devices ud ON u.id = ud.user_id\n" +
"WHERE ud.access_token IS NOT NULL AND ud.user_id <> 1\n" +
"ORDER BY calculateDistanceByLatLong(:userLat, :userLong, ud.latitude, ud.longitude) ASC \n#pageable\n",
countQuery = "SELECT COUNT(DISTINCT u.id) FROM users u \n" +
"INNER JOIN user_devices ud ON u.id = ud.user_id\n" +
"WHERE ud.access_token IS NOT NULL AND ud.user_id <> 1 \n#pageable\n")
public Page<LocationProjection> listNearByUsers(#Param("userLat")String userLatitude,#Param("userLong") String userLongitude, Pageable pageable) throws Exception;
I got the reference from this link.
And also reviewed this link.
But it's not adding any pagination code.
When I try to use :
userDao.listNearByUsers(userDeviceEntity.getLatitude(),userDeviceEntity.getLongitude(), PageRequest.of(pageNo, maxResults))
And for example set pageNo=0 and maxResults =1,all the results are displayed. So no pagination is being implemented.
I printed the fired query, it is :
SELECT
DISTINCT ud.latitude,
ud.longitude,
u.user_id userId
FROM
users u
INNER JOIN
user_devices ud
ON u.id = ud.user_id
WHERE
ud.access_token IS NOT NULL
AND ud.user_id <> 1
ORDER BY
calculateDistanceByLatLong(?,
?,
ud.latitude,
ud.longitude) ASC #pageable
And the count query as :
SELECT
COUNT(DISTINCT u.id)
FROM
users u
INNER JOIN
user_devices ud
ON u.id = ud.user_id
WHERE
ud.access_token IS NOT NULL
AND ud.user_id <> 1 #pageable
I thought Spring Data would add "LIMIT 0,1" in the main query but it's not working. The DAO interface is :
#Repository
public interface UserDao extends JpaRepository<UserEntity, Integer>{}
Please suggest some solution.
After going over several Q/A here, and none working properly (for my setup, at least). After reading this bit at Spring official documentation, I've managed to get it working by simply removing the "pageable" bit from my query.
I'm working with spring-boot version 2.0.1.RELEASE.
public interface UserRepository extends JpaRepository<User, Long> {
#Query(value = "SELECT * FROM USERS WHERE LASTNAME = ?1",
countQuery = "SELECT count(*) FROM USERS WHERE LASTNAME = ?1",
nativeQuery = true)
Page<User> findByLastname(String lastname, Pageable pageable);
}

JPA JOIN query list giving only one item instead of all items

the following sub is giving me only one item( Carte) from the database instead of giving me all of the items . i have spent hours trying to find the error please help me guys
#Path("userid/{clientid}")
#Produces({"application/xml", "application/json"})
public ArrayList<Carte> findUserid(#PathParam("clientid") Integer clientId) {
Utilisateur u1 = new Utilisateur();
u1.setId(clientId);
ArrayList<Carte > arraycarte= new ArrayList<Carte >();
Query query1=em.createQuery("select ca FROM Carte ca left join Compte c on c=ca.compteid left join Utilisateur u on u= c.clientid where u.id=:clientid");
arraycarte.addAll(query1.setParameter("clientid", u1.getId()).getResultList());
return arraycarte;
}
Here is your query:
SELECT ca
FROM Carte ca LEFT JOIN
Compte c
ON c = ca.compteid LEFT JOIN
Utilisateur u
ON u = c.clientid
WHERE u.id = :clientid;
Your where clause is undoing the LEFT OUTER JOIN, because the result is NULL when the user does not match. You can fix this by moving it to the ON clause:
SELECT ca
FROM Carte ca LEFT JOIN
Compte c
ON c = ca.compteid LEFT JOIN
Utilisateur u
ON u.id = c.clientid AND u = :clientid;
You say your query works, but it seems odd that you are referring to table names as column names. I assume this is the result of a typo. In other words, I would expect a query like this:
SELECT ca.*
FROM Carte ca LEFT
-----------^
Compte c
ON c.compte_id = ca.compteid
----------------------^ LEFT JOIN
Utilisateur u
ON u.id = c.clientid AND u.id = :clientid;
------------------------------^

Categories