Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Hibernate中实体的高效更新_Java_Hibernate_Spring Mvc - Fatal编程技术网

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