Java Hibernate中实体的高效更新
我想这可能是个新手问题,但我还是想知道一些答案 假设存在实体:医院和医生(多对多)。假设在我的控制器类中,我必须获取所有现有的医生和医院,然后在特定的医院雇佣一名医生Java Hibernate中实体的高效更新,java,hibernate,spring-mvc,Java,Hibernate,Spring Mvc,我想这可能是个新手问题,但我还是想知道一些答案 假设存在实体:医院和医生(多对多)。假设在我的控制器类中,我必须获取所有现有的医生和医院,然后在特定的医院雇佣一名医生 @Controller public class HospitalController { ... @RequestMapping("/hireDoctor") public String (HttpServletRequest request, Model model) { List<H
@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);
}
..
}
@控制器
公立医院管制员{
...
@请求映射(“/hiredotor”)
公共字符串(HttpServletRequest请求,模型){
列出医院=hospitalService.findAllHospitals();
列出医生=doctorService.findAllDoctors();
//根据逻辑,最终我们只选择了一名医生和一家医院
医生=医生。获取(0);
医院=医院。获取(0);
医院服务。雇工(医院、医生);
}
...
@服务
公立医院服务{
..
@交易的
公共租赁人(医院、医生){
//理想的
列出医生=医院。获取医生();
医生。添加(医生);
这个.em.merge(医院);
}
..
}
它当然不起作用,因为——据我所知——我已经在我的控制器中获取了所有医生和医院,然后在HiredActor方法中,我们打开了传递常规Java对象的事务,这些对象不在会话中
我知道,我可以用一个特定的ID再次找到医院,用一个特定的ID找到医生,然后保存它
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);
}
public void雇佣工(医院、医生){
Hospital h=hospitalRepo.getHospitalById(Hospital.getId());
医生d=hospitalRepo.getDoctorById(Doctor.getId());
列出医生=h.getDoctors();
添加(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;
}
这里的关键点是使用:
获取一个实例,该实例的状态可能是延迟获取的
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;
}
getdocuments()公共集合{
收集结果=新的ArrayList(doctors.size());
用于(医院医生:医生){
add(hospitalToDoctor.getDoctor());
}
返回结果;
}
引入HospitalToDoctor
的另一个好处是,如果需要,您可以轻松地在其中存储其他属性(如医生开始在医院工作时等)
但是,如果您仍然不想引入单独的实体,而是想使用干净的Hibernate多对多,您仍然可以从代理中获益。您可以向加载的
医院添加医生代理(反之亦然)。在将医生
添加到医院
时,您可能还希望查看以避免加载医生
集合,反之亦然(我想这是您问题的主要关注点).一个明显的解决方法是使用SQLQuery并在doctor_hospital表中插入一行。但我仍然对类似Hibernate的解决方案感到好奇——我想二级缓存可能会有所帮助。
public Collection<Doctor> getDoctors() {
Collection<Doctor> result = new ArrayList<>(doctors.size());
for (HospitalToDoctor hospitalToDoctor : doctors) {
result.add(hospitalToDoctor.getDoctor());
}
return result;
}