Effective update of the object in sleep mode

I think it might be like a question for beginners, but still I would like to know some answers.

Let's say there are entities: a hospital and a doctor ( many-to-many ). Suppose in my controller class I have to pick up all existing doctors and hospitals, and then hire one doctor in a particular hospital.

@Controller public class HospitalController { ... @RequestMapping("/hireDoctor") public String (HttpServletRequest request, Model model) { List<Hospital> hospitals = hospitalService.findAllHospitals(); List<Doctor> doctors = doctorService.findAllDoctors(); //some logic, in the end we choose just one doctor and one hospital Doctor doctor = doctors.get(0); Hospital hospital = hospitals.get(0); hospitalService.hireDoctor(hospital, doctor); } ... @Service public class HospitalService { .. @Transactional public void hireDoctor(Hospital hospital, Doctor doctor) { //ideally List<Doctor> doctors = hospital.getDoctors(); doctors.add(doctor); this.em.merge(hospital); } .. } 

Of course, this will not work, because, as I understand it, I took all the doctors and hospitals in my controller, and then in the rentDoctor method we open trasaction, passing ordinary Java objects that are not in the session.

I know that I can simply return the hospital with the speicfic identifier, and Doctor with the specific identifier, and then save it

 public void hireDoctor(Hospital hospital, Doctor doctor) { Hospital h = hospitalRepo.getHospitalById(hospital.getId()); Doctor d = hospitalRepo.getDoctorById(doctor.getId()); List<Doctor> doctors = h.getDoctors(); doctors.add(d); } 

But it just looks like trash.

So - how should such an update look like the most effective?

+2
java spring-mvc hibernate
source share
1 answer

There is a nice and elegant way to do this. It relies on the use of Hibernate proxies in conjunction with extracting a many-to-many relationship to a single object, for example:

 @Entity public class HospitalToDoctor implements Serializable { @Id @ManyToOne private Hospital hospital; @Id @ManyToOne private Doctor doctor; } @Entity public class Hospital { @OneToMany(mappedBy = "hospital") private Collection<HospitalToDoctor> doctors; } @Entity public class Doctor { @OneToMany(mappedBy = "doctor") private Collection<HospitalToDoctor> hospitals; } 

Now, to map a Doctor and a Hospital just one insert instructor without any additional database calls:

 HospitalToDoctor hospitalToDoctor = new HospitalToDoctor(); hospitalToDoctor.setHospital(entityManager.getReference(Hospital.class, hospitalId)); hospitalToDoctor.setDoctor(entityManager.getReference(Doctor.class, doctorId)); entityManager.persist(hospitalToDoctor); 

The key point here is to use EntityManager.getReference :

Get an instance whose state can be lazily retrieved.

Hibernate will simply create a proxy server based on the provided id without getting the entity from the database.

In other use cases, you can encapsulate the HospitalToDoctor object so that the association is still used as many-to-many. For example, you can add something like this to Hopsital :

 public Collection<Doctor> getDoctors() { Collection<Doctor> result = new ArrayList<>(doctors.size()); for (HospitalToDoctor hospitalToDoctor : doctors) { result.add(hospitalToDoctor.getDoctor()); } return result; } 

An additional advantage of introducing HospitalToDoctor is that you can easily store additional attributes in it if such a need arises (for example, when the doctor started working in the hospital, etc.).

However, if you still do not want to enter a separate object, but want to use pure Hibernate many-to-many, you can still use proxies. You can add the Doctor proxy to a busy Hospital (or vice versa). You can also look at Hibernate for additional lazy collections to avoid loading the doctors collection when adding Doctor to Hospital or vice versa (the main problem of your question, I suppose).

+2
source share

All Articles