我遇到了这样的情况,我需要将分离的对象重新附加到hibernate会话,尽管会话中可能已经存在相同标识的对象,这将导致错误。

现在,我可以做两件事之一。

getHibernateTemplate()。更新(obj) 当且仅当对象在hibernate会话中还不存在时,这才有效。当我以后需要它时,抛出异常,声明具有给定标识符的对象已经存在于会话中。 getHibernateTemplate()。合并(obj) 当且仅当hibernate会话中存在对象时,此操作才有效。如果稍后使用此方法,则在需要对象处于会话中时抛出异常。

对于这两种场景,我如何将会话附加到对象?我不想使用异常来控制这个问题解决方案的流程,因为一定有更优雅的解决方案……


当前回答

我想出了一个解决方案,从持久存储中“刷新”一个对象,这将解释其他可能已经附加到会话的对象:

public void refreshDetached(T entity, Long id)
{
    // Check for any OTHER instances already attached to the session since
    // refresh will not work if there are any.
    T attached = (T) session.load(getPersistentClass(), id);
    if (attached != entity)
    {
        session.evict(attached);
        session.lock(entity, LockMode.NONE);
    }
    session.refresh(entity);
}

其他回答

我想出了一个解决方案,从持久存储中“刷新”一个对象,这将解释其他可能已经附加到会话的对象:

public void refreshDetached(T entity, Long id)
{
    // Check for any OTHER instances already attached to the session since
    // refresh will not work if there are any.
    T attached = (T) session.load(getPersistentClass(), id);
    if (attached != entity)
    {
        session.evict(attached);
        session.lock(entity, LockMode.NONE);
    }
    session.refresh(entity);
}

要重新连接该对象,必须使用merge();

这种方法在参数中接受你的实体分离,并返回一个实体将被附加并从数据库中重新加载。

Example :
    Lot objAttach = em.merge(oldObjDetached);
    objAttach.setEtat(...);
    em.persist(objAttach);

所有这些答案都忽略了一个重要的区别。update()用于(重新)将对象图附加到Session。你传递给它的对象是被管理的对象。

merge() is actually not a (re)attachment API. Notice merge() has a return value? That's because it returns you the managed graph, which may not be the graph you passed it. merge() is a JPA API and its behavior is governed by the JPA spec. If the object you pass in to merge() is already managed (already associated with the Session) then that's the graph Hibernate works with; the object passed in is the same object returned from merge(). If, however, the object you pass into merge() is detached, Hibernate creates a new object graph that is managed and it copies the state from your detached graph onto the new managed graph. Again, this is all dictated and governed by the JPA spec.

就“确保该实体受到管理,或者使其受到管理”的通用策略而言,这在某种程度上取决于您是否还想考虑尚未插入的数据。假设你这样做,使用一些类似

if ( session.contains( myEntity ) ) {
    // nothing to do... myEntity is already associated with the session
}
else {
    session.saveOrUpdate( myEntity );
}

注意,我使用的是saveOrUpdate()而不是update()。如果您不想在这里处理尚未插入的数据,请使用update()来代替…

对不起,似乎不能添加评论(还?)。

使用Hibernate 3.5.0-Final

尽管已经弃用了session# lock方法,但javadoc建议使用session# buildLockRequest(LockOptions)#lock(entity),如果您确保您的关联具有cascade=lock,惰性加载也不是问题。

我的attach方法看起来有点像

MyEntity attach(MyEntity entity) {
    if(getSession().contains(entity)) return entity;
    getSession().buildLockRequest(LockOptions.NONE).lock(entity);
    return entity;

初步测试表明它很有效。

直截了当的回答:您可能正在寻找一个扩展的持久性上下文。这是Seam框架背后的主要原因之一…如果您特别纠结于在Spring中使用Hibernate,请查看Seam的这篇文档。

外交回答:这在Hibernate文档中有描述。如果你需要更多的说明,请参阅Hibernate的Java持久化第9.3.2节“使用分离对象”。如果您正在使用Hibernate做CRUD以外的事情,我强烈推荐您阅读这本书。