Hibernate-清除包含所有删除孤立项的集合,然后将其添加到集合中会导致ConstraintViolationException

Hibernate-清除包含所有删除孤立项的集合,然后将其添加到集合中会导致ConstraintViolationException,hibernate,unique-constraint,Hibernate,Unique Constraint,我有这些实体 class Foo{ Set<Bar> bars; } class Bar{ Foo parent; String localIdentifier; } 使用它们的代码是: //foo is persistent, foo id = 1 Bars bars = foo.getBars(); bars.clear(); // bars contained 1 item [parent_id = 1, local_identifier = "a"

我有这些实体

class Foo{
    Set<Bar> bars;
}

class Bar{
    Foo parent;
    String localIdentifier;
}
使用它们的代码是:

//foo is persistent, foo id = 1
Bars bars = foo.getBars();
bars.clear(); // bars contained 1 item [parent_id = 1, local_identifier = "a"]
Bar newBar = new Bar();
newBar.setParent(foo);
newBar.setLocalIdentifier("a");
bars.add(newBar);
现在,由于某种原因,Hibernate没有按照调用的顺序执行。它不会在
add()
(insert)之前执行
clear()
(delete),反之亦然,它首先尝试插入,得到一个
ConstraintViolationException

我知道在
bar.clear()之后添加一点
session.flush()
,可以修复此问题,但在这种情况下,我无法以非丑陋的方式访问会话

那么,冲洗是唯一的解决办法吗?或者是否有一个遵守操作顺序的Hibernate版本

更新: 顺便说一句,取消对集合的引用将导致以下对象的HibernateException:

我会冬眠例外:不要 取消对集合的引用 cascade=“全部删除孤立项”此 如果加载对象时使用 a cascade=“全部删除孤立项” 集合,然后删除 对集合的引用。不要 若要替换此集合,请使用clear() 因此,孤儿删除算法可以 检测您的变化


如果要避免刷新此处的会话,请尝试替换整个列表(
new list()
,而不是
Clear()
)。Hibernate实际上应该在添加新项目之前一次性删除所有项目。只是一次尝试,不确定它是否有效。

我想除了冲水没有别的选择

发件人:

Hibernate违反了唯一约束 Hibernate并不完全是这样 巧妙地使用独特的约束 是用外键的。有时候你 可能需要给点提示

可能会出现唯一的约束冲突 如果两个对象同时处于活动状态,则发生 更新后,一个是“释放”一个值 另一个是“获得”相同的信息 价值一种解决方法是刷新 更新会话后手动执行会话 第一个对象,在更新 第二

(这种问题在中国很少发生 练习。)


如果您使用的是oracle,那么还可以使用可延迟约束来推迟对约束的检查,直到提交事务为止。不确定其他数据库是否/如何支持此功能。

我遇到了一个稍微类似的问题,在特定条件下,我在子表上有一个唯一的索引。所以我的问题是,当我删除一条满足这个条件的记录,然后添加另一条将恢复那个条件的记录时,我得到了唯一的索引问题

经过多次尝试和建议。我不喜欢删除后和添加前刷新的想法,但我认为它会起作用,我找到了一个约束解决方案,删除了唯一索引(因为我实际上不需要对列进行索引),该索引确实起作用:

(关于postgres数据库)

最初推迟是这里的关键

我使用的示例代码:

//Transaction 1
Foo parent = new Foo('some-id');
boolean condition = true;
Bar c = new Bar('some-id', parent, condition);
parent.getChildren().add(c);
fooService.save(parent);    //children list are cascaded
。。。后来

//Transaction 2
boolean condition = true;
Foo parent = fooSerice.findById('some-id');    //children list is eagerly fetched
Bar c1 = parent.getChildren().stream().filter(c -> c.getId().equals("some-id")).findFirst().get();
Bar c2 = new Bar('some-id1', parent, condition);
parent.getChildren().remove(c1);
parent.getChildren().add(c2);

我认为冲洗是唯一的选择。
ALTER TABLE bar ADD CONSTRAINT bar_uc
        EXCLUDE (parent_id WITH =) WHERE (condition = true) INITIALLY DEFERRED;
//Transaction 1
Foo parent = new Foo('some-id');
boolean condition = true;
Bar c = new Bar('some-id', parent, condition);
parent.getChildren().add(c);
fooService.save(parent);    //children list are cascaded
//Transaction 2
boolean condition = true;
Foo parent = fooSerice.findById('some-id');    //children list is eagerly fetched
Bar c1 = parent.getChildren().stream().filter(c -> c.getId().equals("some-id")).findFirst().get();
Bar c2 = new Bar('some-id1', parent, condition);
parent.getChildren().remove(c1);
parent.getChildren().add(c2);