【问题标题】:JPA2 Lazy Child Collection with orphanRemoval=true deletes 'not-fetched' children带有 orphanRemoval=true 的 JPA2 Lazy Child Collection 删除“未获取”的孩子
【发布时间】:2011-07-12 22:13:01
【问题描述】:

我有一个父实体(通过 mappedBy)拥有一个带有 orphanDelete=true 的 FetchType.LAZY Set

客户端可以通过父级的集合 getter 愉快地添加和删除子行,并且在 em.merge(parent) 之后正确提交它们的更改。

但是,如果客户端合并父级而不访问子集合,则所有子行都会在父级提交时被删除。

在 OpenJPA 2.1.0 和 2.1.1-20110610.205956-18 快照二进制文件下表现出相同的行为。

任何指针将不胜感激。

举例说明:

@Entity
public class Parent{

    @Column
    private String name;

    @OneToMany(mappedBy="parent", fetch=LAZY, cascade = ALL, orphanRemoval=true)
    private Set<Child> children;

    public String getName(){return name;}
    public void setName(String name){this.name=name;}

    public Set<Child> getChildren(){
        return children;
    }
}

@Entity
public class Child{

    @ManyToOne(optional = false, targetEntity = Parent.class)
    @JoinColumn(name="parent_id", nullable=false)
    private Parent parent;

}

两个实体都声明了 @Id 和 @Version 属性,并实现了适当的 hashCode、equals 和 compareTo 方法。

以下客户端代码完美运行,更新了 parent.name,插入了 1 个子项,删除了 1 个子项

EntityTransaction eTx=em.getTransaction();
eTx.begin();

Parent par=em.find(Parent.class, parId);
    //PersistenceUnitUtil.isLoaded(par) returns true
    //PersistenceUnitUtil.isLoaded(par, "children") returns false
Collection<Child> children=par.getChildren();
    //PersistenceUnitUtil.isLoaded(par, "children") returns true
Child child = children.iterator().next();
par.getChildren().remove(child);
par.getChildren().add(new Child(par, "I'm New"));
par.setName("I am Updated");
par=em.merge(par);

eTx.commit();

以下代码将为每个父级的子级发出删除命令:

EntityTransaction eTx=em.getTransaction();
eTx.begin();

Parent par=em.find(Parent.class, parId);
   //PersistenceUnitUtil.isLoaded(par) here returns true, and
   //PersistenceUnitUtil.isLoaded(par, "children") returns false
par.setName("I am Updated");
par=em.merge(par);
eTx.commit();

【问题讨论】:

  • EclipseLink 2.2.0.v20110202-r8913 按预期工作,一定是 OpenJPA 错误。
  • 很高兴得知这一点。我打算在休眠状态下尝试它。有没有办法可以通过stackoverflow通知我?我还没弄明白。

标签: java jpa-2.0 openjpa


【解决方案1】:

只是不要调用合并。没有必要。在事务范围内,对在该事务中查找的对象所做的更改将被持久化,除非该对象被分离。

【讨论】:

  • 实际实现比图示稍微复杂一点。客户端使用 DAO 对象进行 crud 操作,因此合并(实体)调用将在不同的事务中,但结果是相同的。如果在 merge(parent) 之前不访问惰性集合,则会删除子集合。
  • 在黑暗中刺探:您的对象在事务之间存储在哪里?也许有人正在用 ArrayList 之类的东西替换持久的子集合?
  • 一切都在模拟操作环境的junit测试下运行。 @BeforeClass 获取一个 dao,保存一些具有特定数量子级的父级,并将父级 ID 写入静态成员。 @Test[one] 得到它的 dao,dao.find(anId),将 getChildren() 写入 System.out,设置 parent.name,dao.save(parent),并断言 getChildren().size()。 @Test[two] 将 getChildren() 省略到 System.out :: 它的断言 getChildren().size() 失败。在我逐步调试调试器时查看数据库日志会显示一个事务,其中包含更新父事务,后跟多个删除子 SQL 语句。
猜你喜欢
  • 2015-11-13
  • 1970-01-01
  • 2015-02-12
  • 2012-10-22
  • 1970-01-01
  • 1970-01-01
  • 2019-04-18
  • 2018-04-02
  • 1970-01-01
相关资源
最近更新 更多