Hibernate - 使用all-delete-orphan清除集合然后添加到它会导致ConstraintViolationException

Era*_*dan 13 hibernate unique-constraint

我有这些实体

class Foo{
    Set<Bar> bars;
}

class Bar{
    Foo parent;
    String localIdentifier;
}
Run Code Online (Sandbox Code Playgroud)

有了这个映射(对不起,没有注释,我很老式):

<class name="Foo">
    ...
    <set name="bars" cascade="all-delete-orphan" lazy="false" inverse="true">
        <key>...</key>
        <one-to-many class="Bar"/>
    </set>
</class>


<class name="Bar">
    ...
    <property name="localIdentifier" column="local_identifier"/>
    <many-to-one name="parent" column="parent_id" />
</class>
Run Code Online (Sandbox Code Playgroud)

我对2列也有一个唯一约束:local_identifierparent_id(不是每个列上的唯一约束,但是包含两者的单个唯一约束,例如,不允许具有相同父和相同localIdentifier的2行)

alter table bar add constraint unique_bar unique (parent_id, local_identifier)
Run Code Online (Sandbox Code Playgroud)

这个代码使用它们:

//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);
Run Code Online (Sandbox Code Playgroud)

现在,由于某种原因,Hibernate不会按照调用顺序执行任务.它不会clear()add()(插入)之前执行(删除),反之亦然,它首先尝试插入,获取一个ConstraintViolationException

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

那么flush是唯一的解决方案吗?还是有一个尊重行动顺序的Hibernate版本?

更新: 顺便说一下,取消引用该集合将导致来自https://www.hibernate.org/117.html#A3的HibernateException :

我得到HibernateException:不要使用cascade ="all-delete-orphan"取消引用集合如果您使用cascade ="all-delete-orphan"集合加载对象,然后删除对集合的引用,则会发生这种情况.不要替换此集合,请使用clear(),以便孤立删除算法可以检测到您的更改.

Era*_*dan 8

我想除了冲洗之外别无选择

这里:

Hibernate违反了一个独特的约束!

Hibernate并不像使用外键那样具有独特的约束.有时您可能需要提供一些提示.

如果两个对象都被更新,一个是"释放"一个值而另一个是"获得"相同的值,则可能发生唯一约束违规.解决方法是在更新第一个对象之后和更新第二个对象之前手动刷新()会话.

(这种问题在实践中很少发生.)