JPA/Hibernate Join Query - java

The goal is to retrieve all users (not messages) that have sent a message to a particular user (the current logged-in user), or have received a message from this user (even if they didn't reply yet). I've tried many queries, but to no avail. (I have the id of the logged-in user).
Do you have any ideas? I'm assuming I need to do a join on Message & RegisteredUser classes, but not sure how it'll work since the Message has the 'sender' & 'receiver' which makes the query a bit more complex.
RegisteredUser class (doesn't have a reference to Message):
#Entity
#Table(name = "USER")
public class RegisteredUser implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
Message class:
#Entity
#Table(name = "MESSAGE")
public class Message implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
int id;
#ManyToOne
#JoinColumn(name = "receiverId")
RegisteredUser receiver;
#ManyToOne
#JoinColumn(name = "senderId")
RegisteredUser sender;
I'm using jpa 2.0 and hibernate 3.5.6.
Thanks!
//EDIT -- The Solution, thanks to Andrey
"select distinct u from RegisteredUser u where u in (select m1.sender from Message m1 join m1.receiver r where r.id = " + user.getId() + ") or u in (select m2.receiver from Message m2 join m2.sender s where s.id = " + user.getId() + ")"

select distinct u from RegisteredUser u where
u in (select m1.sender from Message m1 join m1.receiver r where r.id = " + user.getId() + ") or
u in (select m2.receiver from Message m2 join m2.sender s where s.id = " + user.getId() + ")"

Related

QuerySyntaxException - unexpected token: a (SQL statement not correct?)

I get following error message when trying to fire an SQl Statement....the exception:
QuerySyntaxException: unexpected token: a near line 1, column 127 [SELECT DISTINCT e FROM com.taqwaapps.entity.Event e, com.taqwaapps.entity.Appointment a WHERE e.eventId = a.event.eventIdĀ AND a.district.city.name = 'Jeddah' ]
It seems that following SQL Statement is not correct:
#Query("SELECT DISTINCT e "
+ "FROM Event e, Appointment a "
+ "WHERE e.eventId = a.event.eventIdĀ "
+ "AND a.district.city.name = 'Jeddah' ")
List<Event> getEventsFiltered();
My Objects are:
#Entity
public class Event {
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Long eventId;
}
and
#Entity
public class Appointment {
#JsonIgnore
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "eventId")
private Event event;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "districtId")
private District district;
What is wrong?
I found the Problem:
In the past in school time I learned from my informatics Teacher that in SQL it can happen that there is an hidden character which we entered or which got entered but we dont see it. So just write the SQL again using plain writing

How to query a list of users that share N number of records in a join table with one user

I have an entity (user) that has a List of tracks. I'd like to query all users that share N number of tracks with one user using his id. I'm using Spring Data JPA for my data layer.
I already have a native query that is doing what I want but it's returning a List of ids for the users. I would like to get List instead.
This is my user entity:
#Entity
#Data
#AllArgsConstructor
#NoArgsConstructor
#Builder
#Table(name = "user")
public class User {
#Id
private String id;
private String email;
private String country;
#ElementCollection
#CollectionTable(name = "user_top_tracks",
joinColumns = #JoinColumn(name = "user_id"))
#Column(name = "track_id")
#JsonIgnore
private List<String> tracks;
#ElementCollection
#CollectionTable(name = "user_top_artists",
joinColumns = #JoinColumn(name = "user_id"))
#Column(name = "artist_id")
#JsonIgnore
private List<String> artists;
#ElementCollection
#CollectionTable(name = "matches",
joinColumns = #JoinColumn(name = "user_id"))
#Column(name = "match")
#JsonIgnore
private List<String> matches;
#JsonIgnore
#OneToOne(fetch = FetchType.LAZY, mappedBy = "user", cascade = CascadeType.ALL)
#PrimaryKeyJoinColumn
private Token token;
}
The query I have right now (returning List):
#Query(value = "SELECT that.user_id " +
"FROM user_top_tracks AS this INNER JOIN user_top_tracks " +
"AS that ON that.user_id <> this.user_id " +
"AND that.track_id = this.track_id WHERE this.user_id = ?1 " +
"GROUP BY that.user_id HAVING COUNT(*) >= ?2", nativeQuery = true)
List<String> getMatches(String userId, int matchingTracks);
Database schema
Right now I wrote a method that goes over the return list of ids, fetches them and then adds them to a List of users. It's working fine but I'd like to just make it return a List of users instead.
You just need to add one more join
#Query(value = "SELECT usr.* " +
"FROM user_top_tracks AS this INNER JOIN user_top_tracks " +
"AS that ON that.user_id <> this.user_id " +
"AND that.track_id = this.track_id "+
"JOIN user as usr on that.user_id = usr.id"
"WHERE this.user_id = ?1 " +
"GROUP BY that.user_id HAVING COUNT(*) >= ?2", User.class )
List<User> getMatches(String userId, int matchingTracks);
But I think you can also use JPQL
I ended up doing this and it's working fine.
If i find any better solutions i'll update it.
#Query(value ="SELECT * from user where id IN ("+
"SELECT that.user_id " +
"FROM user_top_tracks AS this INNER JOIN user_top_tracks " +
"AS that ON that.user_id <> this.user_id " +
"AND that.track_id = this.track_id WHERE this.user_id = ?1 " +
"GROUP BY that.user_id HAVING COUNT(*) >= ?2 )", nativeQuery = true)
List<User> getMatches(String userId, int matchingTracks);

Not able to fetch data with left join and join fetch together in JPQL query with entiy graphs as a hint

I am using Jpa 2.2 with Hibernate 5.3.7 final jar. Below are my entities
and code for the test case is not executing correctly:
Instructor Entity :
#Entity
#DynamicUpdate
#DynamicInsert
public class Instructor {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
private int id;
#Version
#Column(columnDefinition = "int(11) not null default 0")
private int version = 0;
**#OneToOne(mappedBy = "instructor", fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
#JoinColumn(name = "proof_id")
private IdProof idProof;
#OneToMany(mappedBy = "instructor", orphanRemoval = true, cascade = CascadeType.ALL)
private Set<Vehicle> vehicles = new HashSet<>();**
IdProof Entity:
#Entity
#Table(name = "id_proof_tbl")
#DynamicInsert
#DynamicUpdate
public class IdProof {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
#Column(updatable = false)
private int id;
#Version
#Column(columnDefinition = "int(11) not null default 0")
private int version;
**#OneToOne(fetch = FetchType.LAZY)
private Instructor instructor;**
Vehicle Entity :
#Entity
#DynamicInsert
#DynamicUpdate
public class Vehicle {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
private int id;
**#ManyToOne(fetch = FetchType.LAZY)
private Instructor instructor;**
**#OneToMany(mappedBy = "vehicle", fetch = FetchType.LAZY, orphanRemoval = true, cascade = CascadeType.ALL)
private Set<Document> documents = new HashSet<>();**
And Documents Entity :
#Entity
#DynamicInsert
#DynamicUpdate
public class Document {
#Id
#GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
#GenericGenerator(name = "native", strategy = "native")
private int id;
**#ManyToOne(fetch = FetchType.LAZY)
private Vehicle vehicle;**
I am fetching data from MySQL database with code described as below as
a JUnit Test:
#Test
#Rollback(false)
#Transactional
public void fetchPartialDataWithJPQLQueryWithEqualEntityGraph() {
**// Preparing Entity Graph to be passed as a hint .**
EntityGraph<Instructor> instructorGraph =
em.createEntityGraph(Instructor.class);
instructorGraph.addAttributeNodes(Instructor_.idProof);
Subgraph<Vehicle> vehcileSubgraph =
instructorGraph.addSubgraph(Instructor_.VEHICLES);
vehcileSubgraph.addAttributeNodes(Vehicle_.documents);
**//Case 1:**
TypedQuery<Instructor> typedQueryJoinFetch =
em.createQuery(" select i from Instructor i "
+ " join fetch i.idProof id "
+ " join fetch i.vehicles v "
+ " join fetch v.documents vd ",
Instructor.class);
typedQueryJoinFetch.setHint("javax.persistence.fetchgraph",
instructorGraph);
List<Instructor> instructors
=typedQueryJoinFetch.getResultList();
**//Case 2:**
TypedQuery<Instructor> typedQueryLeftJoin =
em.createQuery(" select i from Instructor i "
+ " left join i.idProof id "
+ " left join i.vehicles v "
+ " left join v.documents vd ",
Instructor.class);
typedQueryLeftJoin.setHint("javax.persistence.fetchgraph",
instructorGraph);
List<Instructor> instructorsWithLeftJoin =
typedQueryLeftJoin.getResultList();
**// Case 3:**
try {
TypedQuery<Instructor>
typedQueryLeftJoinAndJoinFetchMixed =
em.createQuery(" select i from Instructor i "
+ " join fetch i.idProof id "
+ " left join i.vehicles v "
+ " join fetch v.documents vd ",
Instructor.class);
typedQueryLeftJoinAndJoinFetchMixed.
setHint("javax.persistence.fetchgraph", instructorGraph);
List<Instructor>
instructorsWithLeftJoinAndJoinFetchMixed =
typedQueryLeftJoinAndJoinFetchMixed
.getResultList();
} catch (Exception e) {
e.printStackTrace();
}
}
**Case 1 executes correctly and results in the inner join between the four
tables with below query:**
select
instructor0_.id as id1_2_0_,
idproof1_.id as id1_1_1_,
vehicles2_.id as id1_5_2_,
documents3_.id as id1_0_3_,
instructor0_.address as address2_2_0_,
instructor0_.birth_date_time as birth_da3_2_0_,
instructor0_.birth_date_time_zone_offset as birth_da4_2_0_,
instructor0_.created_date as created_5_2_0_,
instructor0_.day_off_time as day_off_6_2_0_,
instructor0_.day_start_time as day_star7_2_0_,
instructor0_.father_name as father_n8_2_0_,
instructor0_.mother_name as mother_n9_2_0_,
instructor0_.name as name10_2_0_,
instructor0_.photo as photo11_2_0_,
instructor0_.monthly_salary as monthly12_2_0_,
instructor0_.updated_date as updated13_2_0_,
instructor0_.version as version14_2_0_,
idproof1_.address as address2_1_1_,
idproof1_.created_date as created_3_1_1_,
idproof1_.father_name as father_n4_1_1_,
idproof1_.instructor_id as instruc12_1_1_,
idproof1_.is_foreigner as is_forei5_1_1_,
idproof1_.mother_name as mother_n6_1_1_,
idproof1_.name as name7_1_1_,
idproof1_.proof_sequence_no as proof_se8_1_1_,
idproof1_.sex as sex9_1_1_,
idproof1_.updated_date as updated10_1_1_,
idproof1_.version as version11_1_1_,
vehicles2_.creation_date as creation2_5_2_,
vehicles2_.instructor_id as instruct8_5_2_,
vehicles2_.purchased_date_time as purchase3_5_2_,
vehicles2_.purchased_date_zone_offset as purchase4_5_2_,
vehicles2_.student_id as student_9_5_2_,
vehicles2_.updated_date as updated_5_5_2_,
vehicles2_.vechicle_type as vechicle6_5_2_,
vehicles2_.vehicle_number as vehicle_7_5_2_,
vehicles2_.instructor_id as instruct8_5_0__,
vehicles2_.id as id1_5_0__,
documents3_.name as name2_0_3_,
documents3_.vehicle_id as vehicle_3_0_3_,
documents3_.vehicle_id as vehicle_3_0_1__,
documents3_.id as id1_0_1__
from
instructor instructor0_
inner join
id_proof_tbl idproof1_
on instructor0_.id=idproof1_.instructor_id
inner join
vehicle vehicles2_
on instructor0_.id=vehicles2_.instructor_id
inner join
document documents3_
on vehicles2_.id=documents3_.vehicle_id
**Case 2 executes successfully and results in left outer join between
four tables with below query:**
select
instructor0_.id as id1_2_0_,
idproof1_.id as id1_1_1_,
vehicles2_.id as id1_5_2_,
documents3_.id as id1_0_3_,
instructor0_.address as address2_2_0_,
instructor0_.birth_date_time as birth_da3_2_0_,
instructor0_.birth_date_time_zone_offset as birth_da4_2_0_,
instructor0_.created_date as created_5_2_0_,
instructor0_.day_off_time as day_off_6_2_0_,
instructor0_.day_start_time as day_star7_2_0_,
instructor0_.father_name as father_n8_2_0_,
instructor0_.mother_name as mother_n9_2_0_,
instructor0_.name as name10_2_0_,
instructor0_.photo as photo11_2_0_,
instructor0_.monthly_salary as monthly12_2_0_,
instructor0_.updated_date as updated13_2_0_,
instructor0_.version as version14_2_0_,
idproof1_.address as address2_1_1_,
idproof1_.created_date as created_3_1_1_,
idproof1_.father_name as father_n4_1_1_,
idproof1_.instructor_id as instruc12_1_1_,
idproof1_.is_foreigner as is_forei5_1_1_,
idproof1_.mother_name as mother_n6_1_1_,
idproof1_.name as name7_1_1_,
idproof1_.proof_sequence_no as proof_se8_1_1_,
idproof1_.sex as sex9_1_1_,
idproof1_.updated_date as updated10_1_1_,
idproof1_.version as version11_1_1_,
vehicles2_.creation_date as creation2_5_2_,
vehicles2_.instructor_id as instruct8_5_2_,
vehicles2_.purchased_date_time as purchase3_5_2_,
vehicles2_.purchased_date_zone_offset as purchase4_5_2_,
vehicles2_.student_id as student_9_5_2_,
vehicles2_.updated_date as updated_5_5_2_,
vehicles2_.vechicle_type as vechicle6_5_2_,
vehicles2_.vehicle_number as vehicle_7_5_2_,
vehicles2_.instructor_id as instruct8_5_0__,
vehicles2_.id as id1_5_0__,
documents3_.name as name2_0_3_,
documents3_.vehicle_id as vehicle_3_0_3_,
documents3_.vehicle_id as vehicle_3_0_1__,
documents3_.id as id1_0_1__
from
instructor instructor0_
left outer join
id_proof_tbl idproof1_
on instructor0_.id=idproof1_.instructor_id
left outer join
vehicle vehicles2_
on instructor0_.id=vehicles2_.instructor_id
left outer join
document documents3_
on vehicles2_.id=documents3_.vehicle_id
But I want to fetch only those instructors having IdProofs present in the database along with their only vehicles having documents present in the database. So I coded case 3. But Case 3 results in below exception:
java.lang.IllegalArgumentException: org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list [FromElement{explicit,not a collection join,fetch join,fetch non-lazy properties,classAlias=vd,role=com.katariasoft.technologies.jpaHibernate.college.data.entity.Vehicle.documents,tableName=document,tableAlias=documents3_,origin=vehicle vehicles2_,columns={vehicles2_.id ,className=com.katariasoft.technologies.jpaHibernate.college.data.entity.utils.Document}}] [ select i from com.katariasoft.technologies.jpaHibernate.college.data.entity.Instructor i join fetch i.idProof id left join i.vehicles v join fetch v.documents vd ]
Please let me know how I can fulfil my case 3 requirement to fetch
All Instructors having IdProofs present In DB along with their only vehicles having documents present in DB.
You would need to join the document without the fetch as hibernate is trying to fetch these for a non-existant vehicle also with that keyword.
em.createQuery(" select i from Instructor i "
+ " join fetch i.idProof id "
+ "left join i.vehicles v "
+ " join v.documents vd ",
Instructor.class);
Now after you get the results, before processing / accessing the documents of a vehicle you would simply check whether Instructor.vehicles is empty and not proceed if true.
Below code fetches Only those instrcutors having IdProof present in
DB . If No Instructor is having idProof present in db then written
query will return empty List as there is inner join between
Instructor and IdProof .
All Instructors not having any vehicle will also be fetched and their
vehicle list will be initialised as empty.
All vehicle not having any document will also be fetched along with
vehicles having atleast one document . Vehicles not having any
document can be avoided in code while processing data .
But if inner join is created between Vehicle and document and if
there is no document present in db then it will make the complete
result empty . As final inner join will be applied on join results
evaluted till yet in db on first three tables Instructor , IdProof and
Vehcile.
try {
TypedQuery<Instructor>
typedQueryLeftJoinAndJoinFetchMixed =
em.createQuery(" select i from Instructor i "
+ " join fetch i.idProof id "
+ " left join i.vehicles v "
+ " left join v.documents vd ",
Instructor.class);
typedQueryLeftJoinAndJoinFetchMixed.
setHint("javax.persistence.fetchgraph", instructorGraph);
List<Instructor>
instructorsWithLeftJoinAndJoinFetchMixed =
typedQueryLeftJoinAndJoinFetchMixed
.getResultList();
} catch (Exception e) {
e.printStackTrace();
}
}

Hibernate query. Cast classes

Have hql query
List<Developer> developers = session.createQuery("from Developer d " +
"left join ProjectDeveloper pd on pd.developer.id = d.id " +
"where pd.project.id = " + project.getId()).getResultList();
it work and get a list of the objects, but not a Developer.
Actually, the object with i get looks like a list of arrays, which includes object arrays, which include developer class objects and ProjectDeveloper (mtm class). Unfortunately I can not place a link with the image, but Schema look like:
developers = {ArrayList#4889} size = 4
\/ 0 = {object[2]4897} //what does this do in ArrayList<**Developer**>>??
-> 0 = {Developer#4901} //This is exactly the class I expect in ArrayList
-> 1 = {ProjectDeveloper}//?????
-> 1 = {object[2]4898}
Developer class:
#Table(name = "developers")
#Entity
public class Developer implements GenerallyTable{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
private long id;
#Column(name = "first_name")
private String name;
#Column(name = "age")
private int age;
#Column(name = "sex")
private boolean sex;
#Column(name = "salary")
private BigDecimal salary;
//...getters + setters
}
How it impossible (how Developer.class transformed in array with unknown structure), and how do I can get exactly ArrayList of Developers?
Try with createQuery with the type defined https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/Session.html#createQuery-java.lang.String-java.lang.Class-
List<Developer> developers = session.createQuery("select d from Developer d " +
"left join ProjectDeveloper pd on pd.developer.id = d.id " +
"where pd.project.id = " + project.getId(), Developer.class)
.getResultList();
Also you should use setParameter methods
List<Developer> developers = session.createQuery("select d from Developer d " +
"left join ProjectDeveloper pd on pd.developer.id = d.id " +
"where pd.project.id = :proj_id", Developer.class)
.setParameter("proj_id", project.getId())
.getResultList();

Filtering the Products of my Caddie with JPQL

My entity Caddiecontains a #OneToMany relation with its Product
#Entity
public class Caddie {
#Id
#GeneratedValue
int id;
#OneToMany
#OrderBy("price")
List<Product> products = new ArrayList<>();
}
#Entity
public class Product{
#Id
#GeneratedValue
int id;
#Column(nullable=false)
String name;
}
I want all products from my caddie that are more expensive than 2$.
I have tried many things including this one :
String query = " SELECT p FROM Product p "
+ "JOIN Caddie c "
+ "WHERE c.id = 1 "
+ "AND p MEMBER OF c.products AND p.price > :price";
Unfortunately, I have two Path there. Trying :
String query = " SELECT c.products FROM Caddie c "
+ "JOIN c.products prods "
+ "WHERE c.id = 1 AND prods.price > :price";
I don't have the objects I wanted.
I could create an Entity named CaddieProduct, but I would like something cleaner.

Categories