HSQL query using limit in join part - spring

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)

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

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

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);

Spring JPA - Is there a good way for inner join between entities or the only way is JPQL?

I have the following Entities:
#Entity
public class Organisation {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// ...
}
#Entity
public class Section{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
// ...
#ManyToOne
#JoinColumn(name = "organisation_id", nullable = false)
private Organisation organisation;
}
#Entity
public class SubSection {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
// ...
#ManyToOne
#JoinColumn(name = "section_id")
private Section section;
}
Now I want to find all SubSections by Organisation Id. Right now I am doing it using JPQL at the SubSectionRepository as above:
public interface SubSectionRepository extends JpaRepository<SubSection, Long>{
#Query(value = "SELECT ss.* FROM sub_section as ss INNER JOIN section as s ON ss.section_id = s.id WHERE s.organisation_id = ?1", nativeQuery = true)
List<SubSection> findByOrganisation(Long organisationId);
}
Is there any way that I can make INNER JOIN using the JpaRepository interface?
Did you try this way
subsectionRepository.findBySectionOrganizationId(long organizationId)
Update your method to
public interface SubSectionRepository extends JpaRepository<SubSection, Long> {
List<SubSection> findBySectionOrganisationId(Long organisationId);
}
Hibernate will generate something like this.
select subsec.*,
from sub_section subsec
left outer join section sec on subsection.section_id=sec.id
left outer join organisation org on section.organisation_id=org.id
where org.id=?
Don't worry about the left join term. It is actually a inner join because you have a where condition with id = on the most right table. Because of that, it effectively becomes a inner join. I.e if there is no record on the right table for that record, it will be ignored.

Spring boot JPA filter by join table

I cant find something concrete in the docs (https://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.query-methods.query-creation)
and no satisfying answere in several blogs.
so here my question.
I have table Entity like:
#Entity
#Table(name = "workstation")
public class Workstation
{
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "userid", nullable = false)
public User user;
}
And the user table Entity:
public class user
{
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
public Integer id;
#Column(name = "age", nullable = false)
public int age
}
Now I would like to have a query in my Repository like this:
public interface WorkstationRepo extends CrudRepository<Workstation, Long> {
findByUserAgeLesserThan(int maxAge);
}
Means I want to find all user who are under a certain age through my Workstation Entity.
And is it possible without a #Query annotation? Or/And how should it look like?
Try this
List<Workstation> findByUserAgeLessThan(int maxAge);
Alternatively you can also write your query
#Query("Select w from Workstation w where w.user.age < :maxAge")
List<Workstation> findByUserAgeLesserThan(#Param("maxAge") int maxAge);
This works:
#Query("SELECT w from Workstation w INNER JOIN w.user u where u.age < ?1")
List<Workstation> findByUserAgeLessThan(int age);
You should have something like this:
#Query("SELECT w from Workstation w INNER JOIN w.user u where u.age < :age")
List<Workstation> findByUserAgeLessThan(#Param("age") int age);
Basically, you need to JOIN the tables using JPQL.

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