Search by list type field in Spring Data to check if empty or not - spring

I have a Project entity and a separate entity to represent a project assigned to a user
public class Project {
// other fields
#OneToMany(fetch = FetchType.LAZY, mappedBy = "project")
private List<UserProject> projectAssignedUsers;
}
public class UserProject {
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "project_id")
private Project project;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id")
private User user;
}
I need to write 2 separate queries that return the list of assigned projects and unassigned projects, this is what I have:
#Query("from Project p where p.country = :country and p.projectAssignedUsers != null order by p.name asc")
List<Project> getAssignedProjectsByCountry(String country, Pageable pageable);
#Query("from Project p where p.country = :country and p.projectAssignedUsers = null order by p.name asc")
List<Project> getUnassignedProjectsByCountry(String country, Pageable pageable);
However, I'm getting this error:
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at or near "."
How could I write such a query?

This is your first query transformed to plain SQL:
select project0_.id as id1_1_, project0_.country as country2_1_, project0_.name as name3_1_ from project project0_
cross join user_project projectass1_
where project0_.id=projectass1_.project_id
and project0_.country='Country'
and (. is not null)
order by project0_.name asc
The problem is here: and (. is not null).
You can fix it using joins:
#Query(value = "from Project as p left join p.projectAssignedUsers as u where p.country = :country and u is not null")
List<Project> getAssignedProjectsByCountry(String country, Pageable pageable);
#Query(value = "from Project as p left join p.projectAssignedUsers as u where p.country = :country and u is null")
List<Project> getUnassignedProjectsByCountry(String country, Pageable pageable);

Related

JPQL: Warning: HHH000183, Join query between two entities in different folders

What is the correct way to create Join query between two entities in different folder without using eg. #OneToOne relation ?
I have two entities
First in entity/folder1
package com.test.test.test.model.entity.folder1;
#Entity
#Table(name = "table1")
public class Table1 {
#Column(name = "code", length = 6, updatable = false)
private String code;
}
And second entity in entity/folder2
package com.test.test.test.model.entity.folder2;
#Entity
#Table(name = "table2")
public class Table2 {
#Column(name = "code", length = 6, updatable = false)
private String code;
#Column(name = "postCode", length = 6, updatable = false)
private String postCode;
}
Query in Repository (Query working but return empty response):
#Query("""
SELECT t1 FROM Table1 t1
JOIN com.test.test.test.model.entity.folder2.Table2 t2 ON t1.code = t2.code
WHERE t2.postCode <> ''
""")
Optional<Customer> test1Query();
Warning:
HHH000183: no persistent classes found for query class: SELECT t1 FROM Table1 t1
JOIN com.test.test.test.model.entity.folder2.Table2 t2 ON t1.code = t2.code
WHERE t2.postCode <> ''
I spent a lot of time to fix this but i dont know how.
Thanks for help
Because this repository interface only Customer table use.
For without using eg. #OneToOne relation, you can try use: EntityManager or Criteria API

Can't solve MultipleBagFetchException

I'm getting MultipleBagFetchException error. I tried to follow this tutorial, but it didn't helped me. https://vladmihalcea.com/hibernate-multiplebagfetchexception/
I have an entity Commodity (simplified)
#Entity
public class Commodity {
#ElementCollection
#CollectionTable
private List<Ingredient> ingredients; // Embeddable
#ManyToMany
private List<CommodityType> commodityTypes;
#OneToMany(mappedBy = "commodity", cascade = CascadeType.ALL)
#MapKey(name = "localizedId.locale")
private Map<Locale, LocalizedCommodity> localizations;
}
I want to load Commodity with ingredients and commodityTypes loaded.
That's my repository:
public interface CommodityRepository extends JpaRepository<Commodity, Long> {
#Query("select e.id from Commodity e")
List<Long> findAllIds(Pageable pageable);
#QueryHints(value = #QueryHint(name = "hibernate.query.passDistinctThrough", value = "false"), forCounting = false)
#Query("select distinct c from Commodity c left join fetch c.ingredients left join fetch c.localizations where c.id in :ids")
List<Commodity> findAllByIdIn(#Param("ids") List<Long> ids);
#QueryHints(value = #QueryHint(name = "hibernate.query.passDistinctThrough", value = "false"), forCounting = false)
#Query("select distinct c from Commodity c left join fetch c.commodityTypes t where c in :com")
List<Commodity> findWithCommodityTypes(#Param("com") List<Commodity> com);
default List<Commodity> findAllFullyLoaded(Pageable pageable) {
return findWithCommodityTypes(findAllByIdIn((findAllIds(pageable))));
}
}
After findWithCommodityTypes call, Commodity i got is not filled with c.ingredients and c.localizations. I'm getting failed to lazily initialize a collection of role Commodity.localizations error.
How do i get Commodity with c.ingredients, c.localizations and c.commodityTypes?

JPA mapping :Primary key column of one table to non Pk/Fk column of another table

#Entity
#Table(name = "TableA")
public class TableAEntity{
#Id
#Column(name = "RUL_ID"
private Integer rulId;
#Column(name = "COMMENT"
private Integer comment;
#OneToOne
#JoinColumn(name = "RUL_ID" referencedColumnName ="PRNT_ID", insertable=false, updatable=false)
private TableBEntity tableB;
//GETTERS AND SETTERS
}
#Entity
#Table(name = "TableB")
public class TableBEntity{
#Id
#Column(name = "ADD_ID"
private Integer addID;
#Column(name = "PRNT_ID"
private Integer prntId;
//GETTERS AND SETTERS
}
There are 2 DB tables.
TableA with primary key as rulId.
TableB with primary key as addID.
I have to implement a customized JOIN query using JPA native query.
Java Code is:
StringBuilder querySql = "select a.rulId, b.prntId from TableA a JOIN TableB b ON a.rulID = b.prntId"
Query tabQuery = entityManager.createNativeQuery(querySql.toString, TableAEntity.class)
List<TableAEntity> entityList = tabQuery.getResultList();
How to establish this OneToOne(TableA:TableB) relationship when they are not linked with any key(pk/fk).
I am unable to map ResultList to my entity class.Primary key of TableA "rulId" always gets linked to PrimaryKey of TableB "addId", wherein I want to get it associated to "prntId".
Can anyone please help on this.
A couple of things to note:
For JPA query, you have to use createQuery (createNativeQuery is for SQL queries);
#Table(name=...) will define the name of the table in the database but not when you write a JPQL query. For that you can use #Entity(name="..."). In your case, it should be #Entity(name="TableA");
The return value of the query is two fields, not TableAEntity. So passing it as parameter to createQuery is wrong;
It's weird to return a.id and b.id. If you want the entities, you can return a and b.
If there is an association between TableA and TableB, for example:
#Entity(name = "TableA")
public class TableAEntity {
...
#OneToOne
#JoinColumn(referencedColumnName ="PRNT_ID", insertable=false, updatable=false)
public TableBEntity tableB;
}
then you can run the following query:
String jpqlQuery = "from TableA a join fetch a.tableB b";
List<TableAEntity> entityList = entityManager.createQuery(jpqlQuery, TableAEntity.class).getResultList()
entityList.foreach( tableAEntity -> {
TableBEntity tabB = tableAEntity.tableB;
});
If there is no association between TableA and TableB:
String jpqlQuery = "select a, b from TableA a JOIN TableB b ON a.rulID = b.prntId";
List<Object[]> entityList = entityManager.createQuery(jpqlQuery).getResultList()
entityList.foreach( row -> {
TableAEntity tabA = (TableAEntity) row[0];
TableBEntity tabB = (TableBEntity) row[1];
});
But if you really just need the ids, this will work too:
String jpqlQuery = "select a.rulId, b.prntId from TableA a JOIN TableB b ON a.rulID = b.prntId";
List<Object[]> entityList = entityManager.createQuery(jpqlQuery).getResultList()
entityList.foreach( row -> {
Integer tabAId = (Integer) row[0];
Integer tabBId = (Integer) row[1];
...
});
Note that you can change the select and mix the two approaches.
But because there is an association between TableAEntity and TableBEntity, you could rewrite all this as:
String jpqlQuery = "from TableA";
List<TableAEntity> entityList = entityManager.createQuery(jpqlQuery,
TableAEntity.class).getResultList()
entityList.foreach( entity -> {
TableAEntity tabA = entity;
TableBEntity tabB = entity.getTableB();
...
});
With or without the association, you can return from the select clause all the combinations of values you need:
select a, b.addID from ...
select a, b from ...

HSQL query using limit in join part

I'm new in Spring Boot. I tried to find an answer for my question on SO and google, but I can't find an exact answer for it.
I'm trying to create a function in my Spring Boot JpaRepository class which returns a Customer by id with a limited number of ascending ordered AccountingLogs related to the Customer.
My line of code in JpaRepository:
#Query("select c from Customer left outer join AccountingLog a on a.customer.id = c.id where c.id= :id")
Customer getWithLimitedNumberOfLastTransactions(#Param("id") Long id, #Param("limit") int limit);
The Customer class only with the relevant code:
#Entity
public class Customer {
//...
#OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#Column(nullable = true)
#JsonManagedReference
private Set<AccountingLog> accountingLogs;
//...
}
The customer class only with the relevant code:
#Entity
public class AccountingLog {
//...
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "customer_id")
#JsonBackReference
private Customer customer;
//...
}
So I'm looking for an HSQL query which selects one customer by id with a specified number (variable named limit) of accounting logs in ascending order (last in first) related to the customer.
Thank you for your help!
You can write a native query in #Query if you are using MySql:
#Query(value="select c from Customer left outer join AccountingLog a on a.customer.id = c.id where c.id= :id limit :limit", nativeQuery = true)
or Oracle:
#Query(value="select c from Customer left outer join AccountingLog a on a.customer.id = c.id where c.id= :id and ROWNUM < :limit", nativeQuery = true)

JPA Join Custom query with OneToMany

I would like to use #Query annotation to create left join query from a entity with a #OneToMany relationship.
Parent entity is :
#Entity
#Table(name="Registration")
public class Registration {
#Column(nullable = false)
#Type(type = "org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
private LocalDate effect;
#OneToMany(targetEntity=Payment.class, cascade=CascadeType.ALL,fetch = FetchType.LAZY)
#JoinColumn(name="uuid")
private List<Payment> payment;
}
Child :
#Entity
#Table(name="Payment")
public class Payment {
#Id
#GeneratedValue(generator = "uuid")
#GenericGenerator(name="uuid", strategy = "uuid2")
#Column(columnDefinition = "BINARY(16)")
private UUID uuid;
}
For DAO, I do like below :
#Query("SELECT p FROM Registration r JOIN r.payment p WHERE r.effect = :effect")
Iterable<Payment> find(#Param("effect") LocalDate effect);
Obviously, its wrong because generated query is :
select payment1_.uuid as uuid1_9_, payment1_.amount as amount2_9_ from registration registrati0_ inner join payment payment1_ on registrati0_.uuid=payment1_.uuid where registrati0_.effect=?
while the relation table has been generated:
For me, the correct query should be something like this :
select p.* from registration r join registration_payment rp on rp.registration = r.uuid join payment p on p.uuid = rp.payment where r.effect = '2015-10-16'
What is the good query syntax please ? Actual query return en empty array.
Finally, I found a solution.
You must describe relation table with #JoinTable :
#JoinTable(
name="registration_payment",
joinColumns = #JoinColumn(name="registration"),
inverseJoinColumns = #JoinColumn(name = "payment")
)
private List<Payment> payment;
Modify #Query not needed :
#Query("SELECT p FROM Registration r JOIN r.payment p WHERE r.effect = :effect")
Generated query is :
select payment2_.uuid as uuid1_9_, payment2_.amount as amount2_9_
from registration registrati0_
inner join registration_payment payment1_ on registrati0_.uuid=payment1_.registration
inner join payment payment2_ on payment1_.payment=payment2_.uuid
where registrati0_.effect=?

Resources