gpt4 book ai didi

java - Hibernate 中的高效更新实体

转载 作者:行者123 更新时间:2023-11-30 08:48:22 25 4
gpt4 key购买 nike

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

假设有实体:医院和医生(多对多)。假设在我的 Controller 类中,我必须获取所有现有的医生和医院,然后在特定医院雇用一名医生

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

它当然不起作用,因为 - 据我所知 - 我已经在我的 Controller 中获取了所有医生和医院,然后在 hireDoctor 方法中我们打开了传递常规 Java 对象的交易,这些对象不在 session 中。

我知道,我可以再次获取具有特定 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);
}

但它看起来很垃圾。

那么 - 这样的更新应该如何才最有效?

最佳答案

有一个很好的优雅的方法来做到这一点。它依赖于使用 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;
}

现在,只用一个插入语句将 DoctorHospital 关联起来,而无需任何额外的数据库往返:

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

这里的重点是使用EntityManager.getReference :

Get an instance, whose state may be lazily fetched.

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 多对多,您仍然可以从代理中受益。您可以向加载的 Hospital 添加一个 Doctor 代理(反之亦然)。您可能还想看看 Hibernate extra lazy collections避免在将 Doctor 添加到 Hospital 时加载 doctors 集合,反之亦然(我认为您的问题的主要关注点)。

关于java - Hibernate 中的高效更新实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32000131/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com