Java 休眠JPA:@OneToMany删除旧的,插入新的而不刷新

Java 休眠JPA:@OneToMany删除旧的,插入新的而不刷新,java,hibernate,jpa,Java,Hibernate,Jpa,事实上,我从来没有完全理解hibernate中的这种行为。 我在一个名为“Parent”的实体中使用@OneToMany关系,其注释如下: @OneToMany(cascade = {CascadeType.ALL, CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }, orphanRemoval = true) @JoinColumn(name = "entity_id", insertable = true, updata

事实上,我从来没有完全理解hibernate中的这种行为。 我在一个名为“Parent”的实体中使用@OneToMany关系,其注释如下:

@OneToMany(cascade = {CascadeType.ALL, CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }, orphanRemoval = true)
@JoinColumn(name = "entity_id", insertable = true, updatable = true, nullable = false)
private List<Child> children;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void deleteAndAdd(Long parentId, Long childId) {
  Parent parent = entityManager.find(parentId);
  for (Iterator it = parent.children.iterator(); it.hasNext();) {
    Child child = it.next();
    if (child.id == childId) {
      it.remove();
    }
  }
  entityManager.flush();
  Child newChild = new Child();
  parent.children.add(newChild);
}

但是,如果新子级与旧子级具有相同的唯一键值,则此操作将失败。因此,基本上,在新实体被持久化之前,旧的子实体似乎没有被正确移除

如果我在删除旧子项和持久化新子项之间添加entityManager.flush(),如下所示:

@OneToMany(cascade = {CascadeType.ALL, CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE }, orphanRemoval = true)
@JoinColumn(name = "entity_id", insertable = true, updatable = true, nullable = false)
private List<Child> children;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void deleteAndAdd(Long parentId, Long childId) {
  Parent parent = entityManager.find(parentId);
  for (Iterator it = parent.children.iterator(); it.hasNext();) {
    Child child = it.next();
    if (child.id == childId) {
      it.remove();
    }
  }
  entityManager.flush();
  Child newChild = new Child();
  parent.children.add(newChild);
}
一切正常。在插入新的子项之前将删除该子项,这是应该的

因为我不想判断hibernate混淆了发送到DB的语句的顺序,所以我必须假设hibernate还有其他一些东西,但事实并非如此。你知道为什么后一个例子有效,而第一个不有效吗

Hibernate版本是3.5。
DB是Mysql InnoDB

Hibernate不知道也不尊重所有数据库约束(例如Mysql唯一约束)。这是一个众所周知的问题,他们不打算在短期内解决

Hibernate对刷新期间操作的发生方式有一个特殊的定义

实体删除总是发生在插入之后。我知道的唯一答案是移除约束或添加额外的齐平


编辑:顺便说一句,定义顺序的原因是,这是确保外键约束(他们确实关心的约束之一)不被违反的唯一方法,即使用户做了一些违反顺序的事情。

为了将来的读者,解决此问题的一种方法是使用延迟约束。PostgreSQL和Oracle支持它们,也许其他RDBMS也支持它们。Hibernate将发出事务中的所有语句,而延迟将确保仅在事务提交时强制执行约束。例如,在PostgreSQL中:

ALTER TABLE company
    ADD CONSTRAINT name_unique UNIQUE (name) DEFERRABLE INITIALLY DEFERRED;

它并不理想,但简单有效。

但是,如果新的子项与旧的子项具有相同的唯一键值,则此操作将失败。:您是说子项的主键与已退出的主键相同吗?实际上不是。例如,子项上有一个复合唯一键,它由'entity_id'FK和实体的另一个值组成,例如'name'。如果我删除了名为“child1”的子项,并添加了一个名为“child1”的新子项,我正在观察所描述的行为。两个子项的FK显然是相同的,以及我设置为相同值的名称。但是,如果旧的在保留新的之前被删除,这应该可以很好地工作。与其删除子项,为什么不使用新的数据更新它,如果两者都有相同的主键?在我看来,刷新模式不是自动的,你能将刷新模式设置为自动吗?还有,当你说它不起作用时,发生了什么?有例外吗?@西班牙人有效点。但不幸的是,这并不能解释我所遇到的行为。PK肯定不一样,但我同意,在大多数情况下,仍然可以进行更新,而不是在需要时删除和插入新对象。但是,如果我们进一步讨论,这个问题通常从接口的规范开始?至少在Parent中的集合中有Child,这就是我调用entityManager的地方。在这种情况下,文档指定在插入之前删除。这让我有些困惑。我相信“collection”元素指的是多对多关联的联接表。我终于发现了一些东西:集合可以包含几乎任何其他Hibernate类型,包括:基本类型、自定义类型、组件和对其他实体的引用。这是一个重要的区别。集合中的对象可以使用“值”语义处理(其生命周期完全取决于集合所有者),也可以是对具有自己生命周期的另一个实体的引用。在后一种情况下,只有两个对象之间的“链接”被认为是集合所持有的状态“仅管理实体的外键字段。在这种情况下,这实际上是有道理的。为什么不理想呢?你能详细说明一下吗?@Michael举个例子,因为这取决于并非所有数据库服务器都支持的特定功能。这应该在Hibernate中得到一般性的解决。