Getting Hibernate entities from inner join on the same entity - java

I am trying to get the last EmergencyJob carried out by each Employee (i.e. the one with the max endTime).
I have the following entities
EmergencyJob
#Entity
#Table(name = "emergencyjobs", schema = "simulator")
public class EmergencyJob {
#Id
private String jobId;
private LocalDate dateLogged;
private LocalTime timeLogged;
private double easting;
private double northing;
private String priority;
private Point location;
#ManyToOne
private Engineer assignedEngineer;
private LocalTime startTime;
private LocalTime endTime;
...
}
Engineer
#Entity
#Table(name = "engineer", schema = "simulator")
public class Engineer {
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
private int engineerId;
private Point homeLocation;
...
}
With the tables are generated by Hibernate I can do what I need in the database using the following query:
SELECT e.*
FROM simulator.emergencyjobs AS e
INNER JOIN (
SELECT
assigned_engineer_engineer_id,
max(end_time) as end_time
FROM simulator.emergencyjobs
GROUP BY assigned_engineer_engineer_id
) AS ee
ON e.assigned_engineer_engineer_id = ee.assigned_engineer_engineer_id
AND e.end_time = ee.end_time
But I can't figure out how to use this to retrieve a list of EmergencyJob entities in Hibernate.
Any help would be appreciated!

This should do the trick (fetch is optional):
select ej
from emergencyJob ej
inner join fetch ej.assignedEngineer e
where ej.endTime = (select max(distinct sej.endTime)
from emergencyJob sej
where sej.assignedEngineer = e)
Also remember to define the join column on EmergencyJob entity:
#ManyToOne
#JoinColumn(name = "assigned_engineer_engineer_id")
private Engineer assignedEngineer;

Related

Hibernate: separate sql query for every collection

I have a Person class that has a collection of Contacts. Everything works ok, I get the list of persons with their contacts. However, in log I see that a separate query is made to read collection of every person. That is too bad.
How to make hibernate make a join to read all the data in one query? I use JPA.
This is the person class:
#Entity
#Table(name = "tbl1")
public class PersonItem implements Serializable{
#Id
#Column(name="col1")
private String guid;
.....
#ElementCollection(targetClass = ContactItem.class,fetch=FetchType.EAGER)
#CollectionTable(name="tbl2",joinColumns=#JoinColumn(name="col2"))
private List<ContactItem> contacts;
....
}
This is the contact class
#Embeddable
#Table(name = "tbl2")
public class ContactItem implements Serializable {
#Column(name="col1")
private String guid;
#Column(name="col3")
private String info;
}
This is the way I get the list of persons:
Query query = em.createQuery("Select p from PersonItem p WHERE p.guid IN (:guids)");
query.setParameter("guids", guids);
List<PersonItem> list=query.getResultList();
And this what I see in log (I have three persons in DB):
Hibernate: select personitem0_.col1 as col1_0_, personitem0_.col4 as col2_0_, personitem0_.col2 as col3_0_, personitem0_.col3 as col4_0_ from tbl1 personitem0_ where personitem0_.col1 in (? , ? , ?)
Hibernate: select contacts0_.col2 as col1_1_0_, contacts0_.col1 as col2_1_0_, contacts0_.col3 as col3_1_0_ from tbl2 contacts0_ where contacts0_.col2=?
Hibernate: select contacts0_.col2 as col1_1_0_, contacts0_.col1 as col2_1_0_, contacts0_.col3 as col3_1_0_ from tbl2 contacts0_ where contacts0_.col2=?
Hibernate: select contacts0_.col2 as col1_1_0_, contacts0_.col1 as col2_1_0_, contacts0_.col3 as col3_1_0_ from tbl2 contacts0_ where contacts0_.col2=?
Please, begin from a more simple mapping. Use plural names, and column prefixes.
#Entity
#Table(name = "persons")
public class Person {
#Id
#Column(name = "f_guid")
private String guid;
#OneToMany(mappedBy = "person", fetch = FetchType.EAGER)
private List<Contact> contacts;
}
#Entity
#Table(name = "contacts")
public class Contact {
#Id
#Column(name = "f_guid")
private String guid;
#Column(name = "f_info")
private String info;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "fk_person")
private Person person;
}
Person is associated to contacts by a foreign key fk_person in the contacts table.
Update
Looks like JPQL overrides a default fetching strategy. You need to specify a fetch explicitly
select p from PersonItem p left join fetch p.contacts WHERE p.guid IN (:guids)
If you have duplicates, cause of joins, you can use distinct
select distinct p from PersonItem p left join fetch p.contacts WHERE p.guid IN (:guids)
Try #Fetch on your relation.
Also i would suggest to use #OneToMany relation int this case
#OneToMany(mappedBy = "person", fetch = FetchType.EAGER)
#Fetch(FetchMode.JOIN) //You can use SUBSELECT as well
private List<ContactItem> contacts;
You can read more about fetching strategies here
fetch-“join” = Disable the lazy loading, always load all the collections and entities.
fetch-“select” (default) = Lazy load all the collections and entities.
batch-size=”N” = Fetching up to ‘N’ collections or entities, Not record.
fetch-“subselect” = Group its collection into a sub select statement.

Mapping result of aggregate query based on JOINs, to Hibernate property

I need get result of aggregate function to entity property. I try to use Hibernate's #Formula anotation, but she has obviously problem with JOINs. Is there any other way how to get result of these query into object properity?
Simplified datamodel
#Entity
#Table(name = "quasar_auditor")
class Auditor(){
#Id
private Long id;
// ...
}
#Entity
#Table(name = "quasar_nando_code")
class NandoCode{
#Id
private Long id;
#ManyToOne
#JoinColumn(name = "parent_id")
private NandoCode parent;
#OneToMany(mappedBy = "parent")
private Set<NandoCode> children;
// ...
}
#Entity
#Table(name = "quasar_auditor_has_nando_code")
class AuditorNandoCode{
#Id
private Long id;
private Auditor auditor;
#ManyToOne(cascade = CascadeType.DETACH)
#JoinColumn(name = "nando_code_id")
private NandoCode nandoCode;
private int categorySpecificTraining;
// ERROR: missing FROM-clause entry for table "nandocode"
#Formula(value = "(select COALESCE(sum(anc.category_specific_training),0) from quasar_auditor_has_nando_code anc "+
"inner join quasar_nando_code nc ON anc.nando_code_id=nc.id "+
"where nc.parent_id = nandoCode.id and anc.auditor_id = auditor.id)")
private int childrenCategorySpecificTraining;
// getter/setters...
}
Values nandoCode.id and auditor.id are properties of this object;
Thanks for advices
First of all, there's no such thing as nanoCode.id nor auditor.id in this query scope.
If you are trying to access AuditorNandoCode.auditor.id inside #Formula in AuditorNandoCode's annotation you should just use column name - in this case, probably, auditor_id.
So, try this annotation:
#Formula(value = "(select COALESCE(sum(anc.category_specific_training),0) from quasar_auditor_has_nando_code anc "+
"inner join quasar_nando_code nc ON anc.nando_code_id=nc.id "+
"where nc.parent_id = nandoCode_id and anc.auditor_id = auditor_id)")

How to get child table rows using parent table ID?

I have two tables: Organization(Parent) and Department(Child).
There is One to Many relationship, and is mentioned in Organization table only.
#Entity
#Table(name="TBL_STD_ORGANIZATION")
public class Organization implements Serializable {
#Id
#GeneratedValue
#Column(name="FLD_ORG_ID")
private Long organizationId;
#Column(name="FLD_ORG_NAME")
private String orgName;
#OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER)
private java.util.List<Department> listOfDepartMents = new java.util.ArrayList<Department>();
}
Below is Department Class:
#Entity
#Table(name="TBL_STD_DEPARTMENT")
public class Department implements Serializable {
#Id
#GeneratedValue
#Column(name = "FLD_DEPARTMENT_ID")
private Long departmentId;
#Column(name = "FLD_DEPARTMENT_NAME")
private String departmentName;
}
I wrote relationship in Parent table, because of it hibernate creates third table.
Now, I have to retrieve departments start with "sa" keyword and in specific organization.
So I want the HQL or SQL query query. I am not getting it how to write such complex query.
Any suggestions?
I'm fairly certain the HQL/JPQL would be:
SELECT d FROM Organization o JOIN o.listOfDepartMents d WHERE d.departmentName LIKE "sa%"

Select only JPA Collection members meeting condition

I'm trying to select entries for Entity A where all of the children in its collection of CReference entities meet a condition. The query I currently have only requires the conditions to be met on at least one of the members.
Current Query
This query currently selects all objects of type A where at least one of the items in its c_references class
SELECT a FROM A a INNER JOIN FETCH a.c_references c_refs INNER JOIN FETCH c_refs.c_reference c_ref WHERE (c_ref.flag_one=TRUE AND c_ref.flag_two=TRUE)
Classes
Class A
#Entity
public class A{
#Id
private UUID a_uuid;
#OneToMany(fetch = FetchType.EAGER)
#JoinColumn(name = "owning_a_uuid")
private List<CReference> c_references;
}
Class CReference
#Entity
// This class keeps references to all of the A objects that have referenced a C object
public class CReference{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long c_reference_id;
#OneToOne
private A a_referencing_c;
#OneToOne
private C c_reference;
}
Class C
#Entity
#Cacheable
public class C{
#Id
private UUID c_uuid;
private Boolean flag_one = false;
private Boolean flag_two = false;
}
Try this:
SELECT a FROM A a
WHERE NOT EXISTS(
SELECT c_refs
FROM CReference c_refs
INNER JOIN c.c_reference c_ref
WHERE
c_refs.a_referencing_c = a
AND (c_ref.flag_one = FALSE OR c_ref.flag_two = FALSE)
)

How to write query in JPQL?

I have a three classes: Doctor, Patient and Consultation.
Both Doctor and Patient classes have a list of consultations as field.
#Entity
public class Consultation {
#Id
#GeneratedValue
private int id;
private Calendar scheduleDate;
private String information;
private String symptoms;
#ManyToOne
private Doctor doctor;
#ManyToOne
private Patient patient;
//...
}
#Entity
public class Patient {
#Id
#GeneratedValue
private int id;
private String name;
private String ssn;
private String address;
#OneToMany(mappedBy = "patient")
private List<Consultation> consultations;
//...
}
#Entity
public class Doctor {
#Id
#GeneratedValue
private int id;
private String name;
private String specialization;
#OneToMany(mappedBy = "doctor")
private List<Consultation> consultations;
//...
}
I want to obtain the patients of a doctor from a single query; that is all the patients that have the same consultation as a doctor. Note that there is no connection between Doctor and Patient.
Is this posible?
select p from Patient p where p.consultations **someKeyword** (select d.consultations from Doctor d where d.id = :doctorId)
If I'm not mistaken someKeyword would be contains if there would be
where list<entity> contains entity
and in if
where entity in list<entity>
but in this case there would be
list someKeyword list
A combination would be:
select p from Patient p where p.consultations contains (select c from Consultation c where c in (select d.consultations from Doctor d where d.id = :doctorId))
but does this make sens?
I am a beginner in JPA and JPQL.
Something like:
select p from Patient p
where exists (
select c from Consultation c
where c.patient = p
and c.doctor.id = :doctorId
)
?
This tutorial might help:
JPA Tutorial
You can use the NamedQuery annotation which looks something like below
#NamedQuery(
name = "findPatientForDoctor",
query = "SELECT c.patient FROM Consultation c WHERE c.doctor.id : id"))
(just check for the syntax of this query alone)
This will give one patient for a doctor id.
Since your association is like Patient have consultations and each consutlation has one to one mapping with Patient and Doctor. Currently there is no relation in your entity model to get all the patients for a doctor. Patient to Doctor is a many to many relation and currently your entity seems not supporting that. I dont think without a patient to doctor relation you can get the records in one single query.

Categories