设置JPA合并的边界()

设置JPA合并的边界(),jpa,merge,eclipselink,Jpa,Merge,Eclipselink,我正在编写允许将对象图从一个数据库迁移到另一个数据库的代码。对象图表示配置,我们实际上是将配置从暂存环境移动到生产环境 图形从源数据库中获取,分离、序列化,然后合并到目标数据库中 到目前为止,这种方法一直很有效,但我有一个难题 我有一个图表,看起来像这样: @Entity class UoObject { @Id private int uoObject; @OneToMany(fetch=FetchType.EAGER, cascade=CascadeType.ALL) pr

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

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

到目前为止,这种方法一直很有效,但我有一个难题

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

@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;
}
@实体
类对象
{
@身份证
私有对象;
@OneToMany(fetch=FetchType.EAGER,cascade=CascadeType.ALL)
私有集属性;
//其他无关领域
}
@实体
类属性
{
@身份证
私有属性;
@OneToOne(可选=true,fetch=FetchType.EAGER,cascade=CascadeType.ALL)
私有UoAttributeObject UoAttributeObject;
}
@实体
类属性对象
{
@身份证
私有属性;
@许多酮
私有对象;
}
因此这里UoObject有一组UoAttributes,这些UoAttributes可能有一个UoAttributeObject,它引用另一个UoObject

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

当我实现这一点时,我预计如果没有关系上的cascade=MERGE,JPA将引发一个错误,指出该对象不存在。甚至,数据库层最终也会抱怨外键。相反,我发现JPA试图插入一个大部分为空的UoObject实例(只设置了键)。我在JPA2.0规范中发现了这一点:

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

似乎源数据库发现目标UoObject不存在,安排了一个实例进行插入(错误),但没有将源UoObject的状态合并到(正确!)


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

如果将@Version添加到对象中会发生什么

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

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


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

我怀疑我被此错误击中了: