设置JPA合并的边界()



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

图形从源数据库中提取,分离,序列化,然后合并到目标数据库中。

到目前为止,这一直很有效,但我有一个棘手的问题。

我有一张图,看起来像这样:

@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可能有一个引用另一个Uo Object的UoAttributeObject。

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可能会有所帮助,但我不知道怎么做。

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

基本上,您正在合并一个损坏的对象图,因此结果可能很难确定。在这些情况下,使用锁定会有所帮助。基本上,您可以在合并一个事务(旧数据库)的更改时查看它,并且它的状态不一致(因为对象在另一个事务中的新数据库上被删除),因此解决此类并发问题的唯一方法是通过锁定。

这看起来确实是一个错误,因为如果对象不存在,并且没有级联合并或级联持续存在,那么它似乎无效,并且应该从合并中抛出错误。但是,如果不使用锁定,就很难知道某个对象是新对象还是已删除的现有对象。

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

最新更新