设置JPA merge()的边界

时间:2012-02-29 11:11:41

标签: jpa merge eclipselink

我正在研究允许将对象图从一个数据库迁移到另一个数据库的代码。对象图表示配置,我们实际上是将配置从暂存环境移动到生产环境。

图表从源DB获取,分离,序列化,然后合并到目标DB。

到目前为止,这种方法运作良好,但我有一个泡菜。

我的图表看起来像这样:

@Entity
class UoObject
{
  @Id
  private int uoObject;

  @OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL)
  private Set<UoAttribute> uoAttribute;

  // Other irrelevant fields
}

@Entity
class UoAttribute
{
  @Id
  private int uoAttribute;

  @OneToOne(optional=true, fetch=FetchType.EAGER, cascade=CascadeType.ALL)
  private UoAttributeObject uoAttributeObject;

}

@Entity
class UoAttributeObject
{
  @Id
  private UoAttribute uoAttribute;

  @ManyToOne
  private UoObject uoObject;
}

所以这里UoObject有一个UoAttributes的集合,这些UoAttributes可能有一个UoAttributeObject引用另一个UoObject。

UoAttributeObjects引用的UoObjects应该已经在目标数据库中。如果他们不是,我想提出一个错误。为清楚起见,我从不希望目标UoObject更新其状态...基本上我只想建立关系。

当我实现这个时,我预计如果没有关系上的cascade = MERGE,JPA会引发错误,说该对象不存在。或者,甚至,数据库层最终会抱怨外键。相反,我发现JPA尝试插入一个基本上空的UoObject实例(只设置了密钥)。我在JPA 2.0规范中找到了这个:

  

如果X是合并到X'的实体,并且引用另一个实体Y,其中未指定cascade = MERGE或cascade = ALL,则从X'导航相同的关联会产生对托管对象Y的引用'具有与Y相同的持久性身份。

源DB似乎发现目标UoObject不存在,调度插入实例(坏),但不合并源UoObject的状态(好!)。

在源数据库端,是否有一种方法可以检测到实体不在数据库中并引发错误?我怀疑生命周期回调@PrePersist和@PreUpdate可能有所帮助,但我看不出如何。

1 个答案:

答案 0 :(得分:0)

如果将@Version添加到UoObject会发生什么?

基本上你正在合并一个腐败的对象图,所以结果很难确定。锁定的使用可以在这些情况下提供帮助。基本上你可以看一下,因为你正在合并来自一个事务(旧数据库)的更改,并且状态不一致(因为在另一个事务中新对象上删除了对象),所以解决这种并发问题的唯一方法是通过锁定。

它看起来像一个bug,因为如果对象不存在,而不是级联合并或级联持久,它似乎无效并且应该从合并中抛出错误。但是,如果不使用锁定,知道某些东西是新对象,还是已删除的现有对象是非常困难的。

你也可以自己检查这段关系。如果UoObject必须存在,那么在合并之前对它进行查找,如果它不存在则抛出错误,或者插入它,或者其他什么。