管理实体/代理与 ORM 的良好使用

Good usage of managed entities / proxies with ORM

我目前正在考虑如何处理我的域对象以及休眠,考虑以下因素:

但是我正在考虑改进我正在做的事情,以减少一点复杂性,或者至少,将复杂性重新定位到更适合的地方,比如实体的相关服务。也许更抽象的事实是我正在使用 ORM。

这是一个通用的 CRUD 服务,我的所有业务服务都继承自该服务。这段代码是为了向您展示当前是如何完成的(注释,为清楚起见删除了日志):

public void create(T entity) {
    this.entityManager.persist(entity);
}
@Transactional(value = TxType.REQUIRED, rollbackOn=NumeroVersionException.class)
public void update(T entity) throws NumeroVersionException{
    try{
        this.entityManager.merge(entity);
    }catch(OptimisticLockException ole){
        throw new NumeroVersionException("for entity "+entity, ole);
    }
}

public T read(int id) {
    return this.entityManager.find(entityClass, id);
}
public void delete(int id) {
    T entity = this.entityManager.getReference(entityClass, id);
    this.entityManager.remove(entity);
    // edit : removed null test thanks to @JBNizet
}

这种实现的问题是,如果我想创建一个对象,然后利用代理的优势,我基本上必须创建它然后重新获取它。当然,查询可能不会访问数据库,而只会访问 hibernat 的缓存(虽然不确定)。但这意味着我仍然不能忘记重新获取代理。

这意味着我泄露了我在幕后使用 ORM 和代理的事实。

所以我正在考虑将我的界面更改为:

public T read(int id);
public T update(T t)throws NumeroVersionException;
public T create(T object);
public void delete(int id);
List<T> list();

意思是一旦我将一个对象传递给这一层,我将不得不使用返回值。 并具体实施更新,如:

public T update(T t){
    if(!(t instanceof [Proxy class goes there])){
        //+ check if it is a detached proxy
        entityManager.merge(t);
    }  
}

由于每次调用合并都会命中数据库,对于一些只涉及大约 10 个实体的操作,这可能很烦人,我不会在带有代理的更新方法中调用它。

当然,我希望有一些边缘情况需要 entityManager 来刷新等等。但我认为这会显着降低我的代码当前的复杂性并更好地隔离问题。

简而言之,我正在尝试的是在服务中重新定位 ORM 代码,这样我就可以隐藏我正在使用 ORM 和代理的事实,并像使用任何其他实现一样使用接口,而不会丢失使用 ORM 的好处。

问题是这样的:

  1. 这个新设计对这个想法来说是个好主意吗?
  2. 我是否遗漏了有关如何正确处理此问题的任何信息?

注意:即使我在谈论性能,我也关心关注点的隔离、可维护性以及不熟悉 ORM 和我所使用的 Java 的开发人员的易用性。

感谢@JBNizet,我现在看得更清楚了:

  • 我应该使用 merge() 方法返回的值。
  • 托管实体并不总是代理。
  • 我不必抽象化我使用托管实体的事实,这将导致代码复杂且低效
  • 我选择了 JPA,我不会换成它,这是真的,除非重写整个模型以代表基于非关系数据库的东西。

所以我只更改原始代码的更新方法,其余的我会保留。