【问题标题】:Setting bounds for a JPA merge()为 JPA 合并()设置边界
【发布时间】:2012-02-29 11:11:40
【问题描述】:

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

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

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

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

@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 相同的持久标识。

似乎源数据库发现目标 UoObject 不存在,安排一个实例进行插入(坏),但没有合并源 UoObject 的状态(好!)。

在源数据库端,有没有办法可以检测到实体不在数据库中并引发错误?我怀疑生命周期回调 @PrePersist 和 @PreUpdate 可能会有所帮助,但我不知道如何。

【问题讨论】:

标签: jpa merge eclipselink


【解决方案1】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-04-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-08
    • 2015-08-18
    • 2011-06-05
    相关资源
    最近更新 更多