How to write query in JPQL? - java

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.

Related

Establishing relationship between three tables

I am building Demo application in which we have three tables and i am using spring-boot data Jpa with mysql. I have following requirement
Table1 name->Student
sid sname srole //columns name
Table2 name->Courses
cid cname ctime //columns name
Table3 name-> Tutioncenter
id Name sid(student table sid) cid(Courses table cid)
#Entity
public class Student{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long sid;
private String sname;
private String srole;
//getter and setter
}
#Entity
public class Courses{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long cid;
private String cname;
private String ctimme;
//getter and setter
}
#Entity
public class Tutioncenter{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "sid", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Student student;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn(name = "cid", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
#JsonIgnore
private Courses courses;
//getter ans setter
}
#Repository
public interface CoursesRepository extends JpaRepository<Courses,Long>{}
#Repository
public interface StudentRepository extends JpaRepostiroy<Student,Long>{}
#Repository
public interface TutionRepository extends JpaRepository<Tutioncenter,Long>{
Page<SecretManager> findBySIdAndCId(Long sId, Pageable pageable);
Optional<SecretManager> findBySecretIdAndSIdAndCId(Long sid, Long cid);
}
Now I can design controller for Student and Courses but how should i design controller of Tutioncenter for crud operations??
The create, read, update operations of both student and courses table should be no relationship with tutioncenter table. Then we only need to consider how to deal with delete operation. Considering data in tutioncenter table, there would be 2 opotions:
Delete all related data in tutioncenter table at the same time.
Do not delete related data, or do not delete imediaterly.
The following are the SQL of delete both table together:
delete c, t from `courses` c join `tutioncenter` t on c.cid = t.cid where id = 1;
For tutioncenter table, I think there may be no update operation according to your business. Therefore we only need to focus on create, read, delete operations.
read operation is as following:
select s.sname, c.cname, c.ctime from `tutioncenter` t join `student` s on s.sid = t.sid join `courses` c on c.cid = t.cid;
delete operation is as following:
delete t from `tutioncenter` t join `student` s on s.sid = t.sid join `courses` c on c.cid = t.cid where t.sid = 1 and t.cid = 2;
insert operation as following:
insert into `tutioncenter` (name, sid, cid)
select 'test3', sid, cid from `student` s, `courses` c where s.sid = 1 and c.cid = 1;
Back to how to design your controller for TutionRepository, I think that should base on how to design your business.
For example, If this demo system is designed only for student and administrator, then you need to consider both situations.
The following are what I could give till now how a student use your system:
Log in. With that said, all operation will have a sid now. Query student.
List all chozen courses. Query all courses have been choozen by this student.
If add new course, get all valid courses, then add chozen course. Query all courses operation. Add courses for this student.
Or delete chozen courses. Delete chozen courses.
To sum up, choosing courses system for student need the following interface:
Query student by name or id. url may be GET /students/<sid> or GET /students/<sname>. If you have login interface, you could use it instead.
Query all valid courses have been choozen by this student's id. GET /students/<sid>/courses
Query all valid courses. GET /courses
Add courses for this student (courses ids and student id). POST /students/<sid>/courses body is cid list like [cid1, cid2]
Delete courses for this student (courses ids and student id). DELETE /students/<sid>/courses/<cid>
The same to analysis what interfaces needed if you want to add a administrator role, who can manage courses and students.
Anyway, all should begin from business requirements.

How to filter select from table by another table by exclusion principle

My application under Spring Boot v1.5.7
I have 3 entities (schematically):
#Entity
public class Word {
#Id
#GeneratedValue
private Integer id
...
}
#Entity
public class UserWordList {
#Id
#GeneratedValue
private Integer id
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToOne
#JoinColumn(name = "word_id")
private Word word;
}
#Entity
public class UserAnotherWordList {
#Id
#GeneratedValue
private Integer id
#ManyToOne
#JoinColumn(name = "user_id")
private User user;
#ManyToOne
#JoinColumn(name = "word_id")
private Word word;
}
And now I need to select all Words for User, but exclude Words placed in user's lists
Native SQL for user_id=1 is
select *
from Word w
left join UserWordList uwl
on w.id = uwl.word_id and uwl.user_id = 1
left join UserAnotherWordList uawl
on w.id = uawl.word_id and uawl.user_id = 1
where uwl.word_id is NULL
and uawl.word_id is NULL
What is a best way to do it? Ideally I would like to use Spring Data features or HQL, but I don't understand how...
UPD
I solve my problem with native query:
#Entity
#NamedNativeQuery(
name = "User.getWordsToProcess",
resultClass = Word.class,
query = "<...native query to select Words...>"
)
public class User {...}
...
public interface UserRepository extends CrudRepository<User, Integer> {
List<Word> getWordsToProcess(Integer userId);
}
Fastest answer is Criteria api (but that is deprecated in hibernate 5.2 and above.)
So you can use Hql :
getSession().createQuery(" select * from UserWordList u left join fetch u.word
left join fetch u.user").list()
And you can use union or create another query to fetch UserAnotherWordList.
Also you can set any restrictions in Hql like below:
Query query = getSession().createQuery(" select * from UserWordList u left join fetch u.word left join fetch u.user us where us.user = :sample").list();
query.setParameter("sample",value);
query.list();

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.

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%"

How Join hibernate Value objects using HQL query?

Hi i'm New to write HQL Query please help me.....
my Hibernate have three ValueObjects ie.
#Entity
#Table(name="user")
public class UserVO {
#Id
#Column(name="S_ID")
private String s_id;
#Column(name="FIRSTNAME")
private String firstName;
private String email;
}
CourseVO class
#Entity
#Table(name="course")
public class CourseVO
{
#Id
#Column(name="S_ID")
public String s_id;
#Column(name="NAME")
public String name;
}
Skillset VO
#Entity
#Table(name="skillset")
public class SkillsetVO
{
#Id
#Column(name="S_ID")
public String s_id;
#Column(name="COURSE_ID")//Foreign Key "USER"
public String course_id;
#Column(name="USER_ID")//Foreign key "COURSE"
public String user_id;
#Column(name="TEACH_EXP")
public String teach_Exp;
}
Now How to get Values of FirstName,NAME,TEACH_EXP values using EMAIL of USER table using HQL query
If you want to use join syntax in HQL you must work out your mapping accordingly as joins are enabled by mapping.
#Entity class A { #OneToMany private List<B> bs; }
#Entity class B { #Basic int n; }
Enables
select b from A a inner join a.b where a = :id
But with your mapping this is not possible. Also bear in mind that in terms of efficiency most of the RDBMs will perform an inner join on a where a.id = b.id.
select u.firstName, c.name, s.teach_Exp
from UserVO u, CourseVO c, SkillsetVO s
where
u.s_id = s.user_id
and c.s_id = s.course_id
and u.email = :email
But I think that you must review you association. Since looks to me that SkillsetVO.user_id should be SkillsetVO.User (an association to a UserVO entity and same for CourseVO).

Categories