Hibernate中的有效更新实体

我想这可能像一个新手问题,但我仍然想知道一些答案。

假设有实体:医院和医生( )。假设在我的控制者班级中,我必须先找所有现有的医生和医院,然后再在特定的医院雇用一名医生

@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);

}

..

}

它当然不起作用,因为-据我了解-

我已经在控制器中获取了所有医生和医院,然后在hireDoctor方法中,我们通过常规Java对象(不在会话中)打开了事务处理。

我知道,我可以再次获取带有特定ID的医院,以及具有特定ID的Doctor,然后将其保存

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);

}

但这看起来只是垃圾。

那么-这样的更新看起来如何最有效?

回答:

有一个很好的方法可以做到这一点。它依赖于结合使用Hibernate代理和提取与一个单独实体的多对多关系,例如:

@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;

}

现在,仅使用一个insert语句来关联a Doctor和a Hospital,而无需进行任何其他数据库往返操作:

HospitalToDoctor hospitalToDoctor = new HospitalToDoctor();

hospitalToDoctor.setHospital(entityManager.getReference(Hospital.class, hospitalId));

hospitalToDoctor.setDoctor(entityManager.getReference(Doctor.class, doctorId));

entityManager.persist(hospitalToDoctor);

这里的关键点是使用EntityManager.getReference:

获取一个实例,其状态可能会延迟获取。

Hibernate只会根据提供的ID创建代理,而无需从数据库中获取实体。

在其他用例中,您可以封装HospitalToDoctor实体,以便仍然使用多对多关联。例如,您可以添加Hopsital如下内容:

public Collection<Doctor> getDoctors() {

Collection<Doctor> result = new ArrayList<>(doctors.size());

for (HospitalToDoctor hospitalToDoctor : doctors) {

result.add(hospitalToDoctor.getDoctor());

}

return result;

}

引入的另一个好处HospitalToDoctor是,如果需要,您可以轻松地在其中存储其他属性(例如,当医生开始在医院工作时等)。

但是,如果您仍然不想引入单独的实体,而是想要使用干净的多对多Hibernate,仍然可以从代理中受益。您可以将Doctor代理添加到已加载的代理中Hospital(反之亦然)。您可能还希望查看Hibernate额外的惰性集合,以避免doctors在将a添加Doctor到a时Hospital反之亦然(反之亦然)(我想这是您问题的主要关注点),以避免加载该集合。

以上是 Hibernate中的有效更新实体 的全部内容, 来源链接: utcz.com/qa/398238.html

回到顶部