1

我正在使用休眠 3.6.3.Final。我有两个关系实体 A 和 B,其单向 ManyToOne 定义为:


@Entity public class A {
...
@Version @Column ( name = "ChangeNumber" )
public Long getVersion() { return version; }
@ManyToOne @JoinColumn( name = "B_ID" )
public B getRelationalB() { return relationalB; }
...
}

@Entity public class B {
@Version @Column ( name = "ChangeNumber" )
public Long getVersion() { return version; }
....
}

现在假设我在 db 中已经有一个 pk id = 1 的 B 实例,然后执行以下操作:


A a = new A();
a.setRelationalB( new B( 1 ) );
session.saveOrUpdate( a ) ;
引发著名的“TransientObjectException:对象引用了未保存的瞬态...”异常。令人惊讶的是,如果@Version @Column 被删除或设为@Transient,上面的代码将完全正常工作。知道为什么我要观察这种行为吗?

4

2 回答 2

1

问题是您没有使用数据库中的实体 B

A a = new A();
// you're instantiating a "new" B with id 1, this is not the same 
// as the "object" you have in the database.
a.setRelationalB( new B( 1 ) );   
session.saveOrUpdate( a ) ;

问题是休眠无法识别您创建的新 B 与存储在数据库中的 B 相同。如果您想知道这背后的原因,请阅读工作单元模式。

尝试做类似的事情

B b = sessions.get(B.class, 1)
A a = new A();
a.setRelationalB( b );
session.saveOrUpdate( a ) ;

另一点:如果你想一次性保存两个对象的新实例,那么你需要做一个cascade

于 2011-05-29T19:35:47.800 回答
0

在添加 @Version 列之后,我也有很多“对象引用了未保存的瞬态......”异常。这是我在我的情况下解决它的方法:

在我的场景中,问题出在外键上。编写代码的目的不是加载引用的对象,而是创建一个新实例并设置主键,希望 Hibernate 能够找到真正的对象。我再说一遍:在@Version 之前它工作得很好。

说明:

考虑在数据库中存在一个B具有 id的类对象,1现在我们正在保存一个新的A.

  • 以前(不好)(在添加@Version 后给出异常):

    a.setB(新 B(1));

    sf.getCurrentSession().save(a);

  • 已修复(运行良好) - 使用 @Version 没有问题:

    a.setB((B) sf.getCurrentSession().get(B.class, 1));

    sf.getCurrentSession().save(a);

在调试 Hibernate 时,我发现当存在 @Version 列时它会进行一些额外的检查。

所以,我相信有这个错误的人要么没有加载他们试图引用的对象(无论如何这是一个更好的做法),要么他们真的试图保存B(例如)的新实例但没有为它配置级联保存。

于 2013-05-30T20:52:36.257 回答