当前位置: 首页 > 知识库问答 >
问题:

Hibernate中有效的更新实体

翟俊茂
2023-03-14

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

假设存在实体:医院和医生(多对多)。假设在我的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);
    }
  ..
}

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

我知道,我可以用一个特殊的身份证再次去医院,用一个特定的身份证去医生,然后保存它

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

但看起来就是垃圾。

共有1个答案

彭鸿文
2023-03-14

有一个很好和优雅的方法来做到这一点。它依赖于使用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语句而不进行任何额外的数据库往返,来分析DoctorHospital:

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

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

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

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

 类似资料:
  • 我有一个批处理过程,它正在为一组实体重新计算数据。通过Hibernate从DB获取实体列表: 当流程运行时,某些实体似乎正在分离,导致两种症状: 当尝试获取惰性数据时,我得到一个异常: 在我的第一次尝试中,我试图通过调用inside

  • 我实现了两个 entites。规则实体和 RestCall 实体如下所示: RuleEntity RestCallEntity 我在 json 终结点中收到一条规则。比我将收到的 json 规则转换为规则实体并调用 当我只是更改规则的名称时,更新工作正常。但是当我更改它的名称时,它看起来像Hibernate尝试创建一个新的重新调用,即使它已经有一个ID。我得到以下异常。 原因:ruleentity

  • 问题内容: 我的桌子上有很多记录(可能超过500 000或1 000 000)。我在此表中添加了一个新列,我需要使用该表中另一列的相应行值为该列中的每一行填充一个值。 我尝试使用单独的事务来选择每100条记录的下一个块并为其更新值,但是例如,要花费数小时来更新Oracle10中的所有记录。 在不使用某些方言特定功能的情况下,在SQL中执行此操作的最有效方法是什么,因此它可在任何地方(Oracle,

  • 我在hibernate search 6中使用elasticsearch时遇到了问题。让我们假设我们有这样的设置: } } 当我第一次持久化EntityA(即被索引的实体)时,EntityB作为EntityA的子实体持久化在elasticsearch索引中。这是可以的。当我直接编辑EntityB并对其进行更改时,问题出现了,这种更改没有传播到elasticsearch索引。我错过了什么吗? 更新1

  • 以下是我要保存(创建/更新)的实体模型: 有两种方法可以更新此实体: < li >第一个更新除< code>notified属性以外的所有属性的人 < li >第二个更新< code>notified属性的仅 有没有办法告诉Hibernate忽略某个特定方法的某些字段?我需要创建两个不同的特定dao方法吗?我是否需要为经典的< code>save方法保留< code>updatable=false

  • 我想看看我是否在正确的轨道上,或者有没有更有效的方法来实现这一点?