Hibernate:集合中删除元素的最佳方法

21
我在使用Hibernate时经常遇到的问题是有一个对象列表(称为listA)需要持久化到实体(myEntity),但需要先将它们与实体上现有的列表进行比较,并删除那些不在listA中的对象。
简单的方法是清除实体上的列表,然后将listA全部添加到实体上,但是通常我需要在删除之前对元素执行一些验证 - 例如,检查这个用户是否被允许删除它们。
我的当前方法感觉很笨拙:
//Delete the elements that have been removed
//Use toArray to avoid ConcurrentModificationException
for(ObjectA a : myEntity.getObjectAList().toArray(new ObjectA[myEntity.getObjectAList().size()])) {
    if(!listA.contains(a)) {

        //Check if this element can be deleted
        if(canDelete(a)) {
            entityManager.remove(a);
            myEntity.getObjectAList().remove(a);
        }
    }
}

//Add the elements that don't already exist
for(ObjectA a : listA) {
    if(!myEntity.getObjectAList().contains(a)) {
        myEntity.getObjectAList().add(a);
    }
}

有哪些可以改进的地方呢?

谢谢。

2个回答

23

我知道这个问题很旧,但我遇到了同样的问题,而且我认为给出的答案不够。所以,你可以通过在映射注释中添加"orphanRemoval=true"属性来达到你想要的精确结果。孤儿删除的工作方式如下(如书籍《使用GlassFish 3开发Java EE 6应用程序》第136页所述:

"[...] 当从一对多关系的集合中删除子实体时,代码会自动删除Address实体,或当顾客被删除或关系被打破(通过将地址属性设置为空或在集合中删除子实体)时也是如此"。

也就是说,如果你从映射了孤儿删除的集合中删除一个项目,然后合并实体,该项目也将被删除。


事情有变化吗?现在已经是2021年了,这是不正确的。我因为orphanRemove=true而遇到了传递给persist的分离实体错误。 - chitgoks

11

尝试使用:

myEntity.getObjectAList().removeAll(listA);

这将仅保留那些尚未在listA中的对象。

此外,如果您将来需要手动执行类似操作,请使用迭代器:

Iterator<?> it = myEntitiy.getObjectAList().iterator();
while (it.hasNext())
{
    ...
}

然后 it.next() 会给你数组中的下一个项,而 it.remove() 将为你删除 next() 的最后一个值,如果你继续循环,它不会抛出异常。

如果在循环时需要添加新值,请考虑使用 listIterator()。


我不能使用removeAll(),因为在删除元素之前需要对它们进行单独的验证。不过感谢您提供的迭代器提示。 - Damo
2
我认为removeAll的重点在于,它会将对象列表修剪为仅包含需要检查删除的项目。之后,你可以检查所有这些项目并进行允许的删除。然后,你可以添加listA中的所有内容而无需检查它们是否已经存在,因为你已经将它们删除了。 - digitaljoel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接