Hibernate中的更新实体 [英] Efficent updating entity in Hibernate

查看:127
本文介绍了Hibernate中的更新实体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  @Controller 
public class HospitalController {
...
@RequestMapping(/ hireDoctor)
public String(HttpServletRequest request,Model model){
List< Hospital>医院= hospitalService.findAllHospitals();
列表< Doctor>医生= doctorService.findAllDoctors();

//一些逻辑,最后我们只选择一名医生和一家医院

Doctor doctor = doctors.get(0);
医院医院= hospitals.get(0);

hospitalService.hireDoctor(医院,医生);



@Service
public class HospitalService {
..
@Transactional
public void hiredctor(医院医生,博士医生){
//理想地
List< Doctor>医生= hospital.getDoctors();
doctors.add(医生);

this.em.merge(医院);
}
..
}

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



我知道,我可以再次通过特殊身份证件和具有特定身份证明的医生取回医院,然后保存它。

  public void hiredoctor(医院医院,医生医生){
医院h = hospitalRepo.getHospitalById(hospital.getId());
Doctor d = hospitalRepo.getDoctorById(doctor.getId());
列表< Doctor>医生= h.getDoctors();
doctors.add(d);
}

但它看起来很垃圾。



所以 - 这样的更新应该如何最有效率?

解决方案

有一种很好的方法可以做到这一点。它依靠使用Hibernate代理,并将多对多关系提取到一个单独的实体,例如:

  @Entity 
public class HospitalToDoctor实现Serializable {
@Id
@ManyToOne
私立医院医院;

@Id
@ManyToOne
私人博士医生;
}

@实体
公立班医院{
@OneToMany(mappedBy =医院)
私人收藏< HospitalToDoctor>医生;
}

@实体
公共类医生{
@OneToMany(mappedBy =doctor)
私人收藏< HospitalToDoctor>医院;

$ / code>

现在,要联合 Doctor 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 中,如下所示:

 公共收藏<博士> getDoctors(){
Collection< Doctor> result = new ArrayList<>(doctors.size()); (HospitalToDoctor hospitalToDoctor:医生)
{
result.add(hospitalToDoctor.getDoctor());
}
返回结果;
}

引入 HospitalToDoctor 是,如果需要出现,你可以很容易地存储其他属性(例如当医生开始在医院工作等)。

然而,如果你仍然不想引入一个单独的实体,但想要使用一个干净的Hibernate多对多,你仍然可以从代理中受益。您可以为 Hospital (或反之)添加 Doctor 代理。您也可以查看 Hibernate额外的懒惰集合,以避免在向医院添加 Doctor 时加载医生 / code>或反之亦然(我认为您的问题的主要关注点)。

I guess it may be like a newbie question, but still I'd like to know some answers.

Let's say there are entities: Hospital and Doctor (Many-To-Many). Suppose in my controller class I have to fetch all existing doctors and hospitals, and then hire one doctor in a specific hospital

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

It of course doesn't work, because - as I understand - I've fetched all doctors and hospitals in my controller and then in hireDoctor method we're opening trasaction passing regular Java objects, which are not in a session.

I know, that I can just again fetch Hospital with a speicfic ID, and Doctor with a specific ID and then save it

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

But it just looks rubbish.

So - how should such update look like to be most efficient?

解决方案

There is a nice and elegant way to do this. It relies on using Hibernate proxies combined with extracting the many-to-many relationship to a separate entity, for example:

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

Now, to asscociate a Doctor and a Hospital with only one insert statement without any additional database round-trips:

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

The key point here is to use EntityManager.getReference:

Get an instance, whose state may be lazily fetched.

Hibernate will just create the proxy based on the provided id, without fetching the entity from the database.

In other use cases you can encapsulate the HospitalToDoctor entity, so that the association is still used as many-to-many. For example, you can add to the Hopsital something like this:

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

The additional benefit of introducing the HospitalToDoctor is that you can easily store additional attributes in it if the need arises (like when a doctor started to work in a hospital, etc).

However, if you still don't want to introduce a separate entity but want to use a clean Hibernate many-to-many, you can still benefit from the proxies. You can add a Doctor proxy to the loaded Hospital (or vice versa). You may also want to look at Hibernate extra lazy collections to avoid loading the doctors collection when adding a Doctor to a Hospital or vice versa (the main concern of your question, I assume).

这篇关于Hibernate中的更新实体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆