how to write join query in hibernate - java

I have created two beans User and VirtualDomain with many to many relationship
#Entity
#Table(name = "tblUser")
public class User implements Serializable {
private Long id;
private String username;
private Set<VirtualDomain> virtualdomainset;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "username", length = 50, nullable = false)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#ManyToMany(targetEntity = VirtualDomain.class, cascade = {CascadeType.PERSIST},fetch=FetchType.EAGER)
#JoinTable(name = "tblUserDomainRel", joinColumns = #JoinColumn(name = "userid"), inverseJoinColumns = #JoinColumn(name = "domainid"))
public Set<VirtualDomain> getVirtualdomainset() {
return virtualdomainset;
}
public void setVirtualdomainset(Set<VirtualDomain> virtualdomainset) {
this.virtualdomainset = virtualdomainset;
}
}
#Entity
#Table(name = "tblVirtualDomain")
public class VirtualDomain {
private Long id;
private String domainname;
private Set<User> userset;
#Id
#JoinColumn(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "domain_name")
public String getDomainname() {
return domainname;
}
public void setDomainname(String domainname) {
this.domainname = domainname;
}
#ManyToMany(cascade = {CascadeType.ALL},fetch=FetchType.EAGER, mappedBy = "virtualdomainset", targetEntity = User.class)
public Set<User> getUserset() {
return userset;
}
public void setUserset(Set<User> userset) {
this.userset = userset;
}
}
how to get data of user like username related to particular domain through hibernate.

To add to gid's answer, if for some reason you need to eagerly fetch an entites relations, then the join syntax would be join fetch.
from VirtualDomain vd join fetch vd.usersset u
where vd.domainname = 'example.com' and u.username like 'foo%'

Always difficult to write HQL without a test system...but here we go:
select u from VirtualDomain vd join User vd.usersset u
where vd.domainname = 'example.com' and u.username like 'foo%'
Let me know how you get on.
One tip I often did prior to buying Intellji was to stop the app in the debugger and then use the immediate window to experiment with HQL.
The hibernate documentation on joins has always been a bit cryptic in my opinion.

Related

Query to sort data based on another entity

I'm writing a site of a hospital. This is an MVC application with database. Database contains data about patients, doctors etc.
I need to get List of doctors which should be sorted by patient count. I have already tried to do this with Comparator inside Java code like this example:
Page<Doctor> pageDoctor = doctorRepository.findAll(pageable);
List<Doctor> doctorList = pageDoctor.getContent();
doctorList.sort(Comparator.comparing(o -> patientRepository.findAllByDoctor(o).size()));
but I need the sorted list inside Page content. I don't really understand how to make the query equivalent to this example, because I'm new to SQL. Here are my entity and repository classes.
Doctor.java
#Entity
#Table(name = "doctors")
public class Doctor {
#Id
#Column(name = "id", nullable = false, unique = true)
#SequenceGenerator(name="doctors_generator", sequenceName = "doctors_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "doctors_generator")
private Long id;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "doctors_type_id")
private DoctorsType doctorsType;
public Doctor(User user, DoctorsType doctorsType) {
this.user = user;
this.doctorsType = doctorsType;
}
public Doctor() {
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public DoctorsType getDoctorsType() {
return doctorsType;
}
public void setDoctorsType(DoctorsType doctorsType) {
this.doctorsType = doctorsType;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
Patient.java
#Entity
#Table(name = "patients")
public class Patient {
#Id
#Column(name = "id", nullable = false, unique = true)
#SequenceGenerator(name="patients_generator", sequenceName = "patients_id_seq", allocationSize = 1)
#GeneratedValue(strategy = GenerationType.AUTO, generator = "patients_generator")
private Long id;
#OneToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "user_id")
private User user;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "doctor_id")
private Doctor doctor;
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "treatment_id")
private Treatment treatment;
public Patient(User user, Doctor doctor, Treatment treatment) {
this.user = user;
this.doctor = doctor;
this.treatment = treatment;
}
public Patient() {
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public Doctor getDoctor() {
return doctor;
}
public void setDoctor(Doctor doctor) {
this.doctor = doctor;
}
public Treatment getTreatment() {
return treatment;
}
public void setTreatment(Treatment treatment) {
this.treatment = treatment;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
PatientRepository.java
#Repository
public interface PatientRepository extends JpaRepository<Patient, Long> {
Patient findPatientByUser(User user);
List<Patient> findAllByDoctor(Doctor doctor);
Patient findPatientById(long id);
Page<Patient> findAllByOrderByIdAsc(Pageable pageable);
List<Patient> findAllByOrderByIdAsc();
}
DoctorRepository.java
#Repository
public interface DoctorRepository extends JpaRepository<Doctor, Long> {
Doctor findDoctorById(long id);
Doctor findDoctorByUser(User user);
#Query(
//sql query there
)
Page<Doctor> findAllByPatientCountAsc(Pageable pageable);
Page<Doctor> findAll(Pageable pageable);
List<Doctor> findAllByOrderByIdAsc();
List<Doctor> findAllByDoctorsTypeNot(DoctorsType doctorsType);
List<Doctor> findAllByDoctorsType(DoctorsType doctorsType);
}
Thanks for your answers in advance.
Check this one:
SELECT d FROM Doctor d,
LEFT JOIN Patient p ON d.id = p.doctor.id
GROUP BY d
ORDER BY COUNT(p.id)

Hiberate one-to-one annotaion builds wrong sql query

I have a small problem with hibernate query with one-to-one relation
I created 3 entities. In case of one-to-one relation user-to-group it works properly. I use property create in hiberanate config and it creates correct table with correct FK.
Creating record work correct too
MyUser user = new MyUser();
user.setLogin("Mark");
user.setPassword("123456");
MyPresence presence = new MyPresence();
presence.setPresenceId(2);
presence.setUser(user);
session.beginTransaction();
session.save(user);
session.save(presence);
session.getTransaction().commit();
session.close();
if get User by presence it works correct
int id = 2;
MyPresence myPresence = session.load(MyPresence.class, id);
System.out.println(myPresence);
But when I'm try to get presence by user result from database hibernate build wrong sql query
int id = 3;
MyUser myUser = session.load(MyUser.class, id);
System.out.println(myUser);
Generated Hibernate sql:
Hibernate: select myuser0_.id as id1_2_0_, myuser0_.group_id as group_id4_2_0_, myuser0_.login as login2_2_0_, myuser0_.password as password3_2_0_, mypresence1_.id as id1_1_1_, mypresence1_.presence_id as presence2_1_1_, mypresence1_.updated_at as updated_3_1_1_, mypresence1_.user_id as user_id4_1_1_ from users myuser0_ left outer join user_presence mypresence1_ on myuser0_.id=mypresence1_.id where myuser0_.id=?
But I expect to see
on myuser0_.id=mypresence1_.user_id instead of on myuser0_.id=mypresence1_.id
MyUser.java
#Entity
#Table(name = "users")
public class MyUser {
private int id;
private String login;
private String password;
private MyGroup group;
private MyPresence presence;
public MyUser() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#Column(name = "login")
public String getLogin() {
return login;
}
public void setLogin(String login) {
this.login = login;
}
#Column(name = "password")
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#JoinColumn(name = "group_id")
#OneToOne(cascade = CascadeType.DETACH, fetch = FetchType.LAZY)
public MyGroup getGroup() {
return group;
}
public void setGroup(MyGroup group) {
this.group = group;
}
#OneToOne(cascade = CascadeType.DETACH)
#JoinColumn(name = "id", referencedColumnName = "user_id")
public MyPresence getPresence() {
return presence;
}
public void setPresence(MyPresence presence) {
this.presence = presence;
}
}
MyPresence.java
#Entity
#Table(name = "presence")
public class MyPresence {
private int id;
private MyUser user;
private int presenceId;
private Date updatedAt;
public MyPresence() {
}
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "id")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
#OneToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "user_id", referencedColumnName = "id")
public MyUser getUser() {
return user;
}
public void setUser(MyUser user) {
this.user = user;
}
#Column(name = "presence_id")
public int getPresenceId() {
return presenceId;
}
public void setPresenceId(int presenceId) {
this.presenceId = presenceId;
}
#Column(name = "updated_at")
public Date getUpdatedAt() {
return updatedAt;
}
public void setUpdatedAt(Date updatedAt) {
this.updatedAt = updatedAt;
}

Hibernate eliminate records and propagation on many to many relationships

I have two connected classes,
Patient:
...
#Entity
#Table(schema="public",name="patient")
public class Patient{
..
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "patient_id")
public Integer getId() {
return Id;
}
public void setId(Integer id) {
Id = id;
}
#ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
#JoinTable(name = "patient_examination", catalog = "ALTAdb", joinColumns = {
#JoinColumn(name = "patient_id", nullable = false, updatable = false) },
inverseJoinColumns = { #JoinColumn(name = "examination_id",nullable = false, updatable = false) })
public Set<Examination> getExaminations() {
return examinations;
}
public void setExaminations(Set<Examination> examinations) {
this.examinations = examinations;
}
...
Examination:
...
#Entity
#Table(schema="public",name="examination")
public class Examination{
..
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "examination_id")
public Integer getId() {
return Id;
}
public void setId(Integer id) {
Id = id;
}
#ManyToMany(fetch = FetchType.EAGER, mappedBy = "examinations")
public Set<Patient> getPatients() {
return patients;
}
public void setPatients(Set<Patient> patients) {
this.patients = patients;
}
...
And when I try to delete a record that is present olso in patient_examination
Code:
public boolean deleteExamination(int ExaminationId){
boolean deleted=false;
Session session=factory.getCurrentSession();
session.beginTransaction();
Query query =session.createQuery("select m from "+ Examination.class.getName() +" m");
List<Examination> examinations= query.getResultList();
for(Examination e: examinations){
if(e.getId()==ExaminationId){
session.delete(e);
deleted=true;
break;
}
}
session.getTransaction().commit();
return deleted;
}
this is my console:
"Examination" violates the external key constraint "fkexas9b9fwxn0t37wl60a4jcd3" on the table "patient_examination"
Detail: The key (examination_id) = (4) is still referenced by the table "patient_examination"
I do not know how to fix it.
I also tried to make a query to directly access to patient_examination, but I do not know a working method for it
Try #ManyToMany with CascadeType.REMOVE it will work as far as I know...

Creating a simple user/group model with permissions with Hibernate (annotations)

This is most likely a very basic question, but nevertheless:
Basically the User entity has an Id and a privilege enum.
The group has an id and a name.
I wonder how to model a relationship where an user can be in multiple groups, having different privilege levels in different groups. Every group can of course have multiple members.
What's the way I'm supposed to solve that idiomatically with Hibernate?
Adding some membership field to User? A membership field to Group? Both? Creating a new class for it? Which annotations are required to wire these things together?
I used next architecture
UserEntity class
#Entity
#Table(name = "user")
public class UserEntity implements Serializable {
private Long user_id;
private String username;
private String password;
public UserEntity() {
}
public UserEntity(String name, String passwd) {
username = name;
password = passwd;
}
#Column(name = "password", nullable = false)
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getUser_id() {
return user_id;
}
public void setUser_id(Long user_id) {
this.user_id = user_id;
}
#Column(name = "username", nullable = false)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
AuthorityEntity class
#Entity
#Table(name = "authority_role")
public class AuthorityEntity implements Serializable {
private Integer id;
private String authority;
private List<UserEntity> people;
public AuthorityEntity() {
}
public AuthorityEntity(String authString) {
authority = authString;
}
#Column(name = "authority", nullable = false)
public String getAuthority() {
return authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToMany(targetEntity = UserEntity.class,
cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinTable(name = "authority_role_people",
joinColumns =
#JoinColumn(name = "authority_role_id"),
inverseJoinColumns =
#JoinColumn(name = "user_id"))
public List<UserEntity> getPeople() {
return people;
}
public void setPeople(List<UserEntity> people) {
this.people = people;
}
}
In fact - this is how implemented spring security plugin.
In your case you can implement that architecture, which will be more useful for you.

how to write delete query in hibernate for many to many relationship

I have two beans user and virtualdomain
#Entity
#Table(name = "tblUser")
public class User implements Serializable {
private Long id;
private String username;
private String deleteflag;
private Set<VirtualDomain> virtualdomainset;
#Id
#Column(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "username", length = 50, nullable = false)
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
#Column(name = "deleteflag")
public String getDeleteflag() {
return deleteflag;
}
public void setDeleteflag(String deleteflag) {
this.deleteflag = deleteflag;
}
#ManyToMany(targetEntity = VirtualDomain.class, cascade = {CascadeType.PERSIST},fetch=FetchType.EAGER)
#JoinTable(name = "tblUserDomainRel", joinColumns = #JoinColumn(name = "userid"), inverseJoinColumns = #JoinColumn(name = "domainid"))
public Set<VirtualDomain> getVirtualdomainset() {
return virtualdomainset;
}
public void setVirtualdomainset(Set<VirtualDomain> virtualdomainset) {
this.virtualdomainset = virtualdomainset;
}
}
#Entity
#Table(name = "tblVirtualDomain")
public class VirtualDomain {
private Long id;
private String domainname;
private String deleteflag;
private Set<User> userset;
#Id
#JoinColumn(name = "id")
#GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
#Column(name = "domain_name")
public String getDomainname() {
return domainname;
}
public void setDomainname(String domainname) {
this.domainname = domainname;
}
#Column(name = "deleteflag")
public String getDeleteflag() {
return deleteflag;
}
public void setDeleteflag(String deleteflag) {
this.deleteflag = deleteflag;
}
#ManyToMany(cascade = {CascadeType.ALL},fetch=FetchType.EAGER, mappedBy = "virtualdomainset", targetEntity = User.class)
public Set<User> getUserset() {
return userset;
}
public void setUserset(Set<User> userset) {
this.userset = userset;
}
}
Now when I delete some user i use to set the deleteflag which means that the data remains in the database.
My requirement is that the user whose delete flag is set must be removed from the tblUserDomainRel table so how to write that delete query.
just remove the virtualDomain from the collection on the User and remove the other side for completeness
// on User
public void removeVirtualDomain(VirtualDomain vd){
virtualDomainset.remove(vd);
vd.getUserset().remove(this)
}
this will remove the relationship record. Or to remove a user from all virtual Domains:
// on User
public void removeFromAllVirtualDomains(){
for( VirtualDomain vd : virtualdomainset ){
vd.getUserset().remove(this);
}
virtualDomainset.clear();
}

Categories