使用@Version列不允许@ManyToOne关系属性作为参考

时间:2011-05-21 18:07:58

标签: hibernate jpa-2.0 optimistic-locking relational-model

我正在使用hibernate 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中已经有一个B实例,pk id = 1,然后执行以下操作:


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

2 个答案:

答案 0 :(得分:0)

问题是您没有使用数据库中的实体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 ) ;

问题在于,hibernate无法识别您创建的新B与存储在db上的新B相同。如果您想知道背后的原因,请阅读Unit of Work模式。

尝试做类似

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

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

答案 1 :(得分:0)

在添加@Version列之后,我有很多“对象引用未保存的瞬态......”异常。 以下是我在案例中解决的问题:

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

龙虎斗:

考虑数据库中存在标识为B的类1的对象,现在我们正在保存A的新实例。

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

    a.setB(new B(1));

    sf.getCurrentSession()保存的(a);

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

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

    sf.getCurrentSession()保存的(a);

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

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