我在 Grails 2.3.7 中使用具有父/子关系的数据绑定(bind),并且在删除时遇到问题。该表单有许多可选的子项,为了保持数据库整洁,我想清除空白(null)值。我发现了一些不错的文章,建议使用 removeAll 过滤我的条目,但我无法让 remove 或 removeAll 工作!
例如......( parent 有10个 child ,5个是空白的)
def update(Parent parent) {
parent.children.getClass() // returns org.hibernate.collection.PersistentSet
parent.children.size() // returns 10
parent.children.findAll{ it.value == null }.size() // returns 5
parent.children.removeAll{ it.value == null } // returns TRUE
parent.children.size() // Still returns 10!!!
}
我读过 PersistentSet 对手动实现 equals() 和 hashCode() 很挑剔,我在每个域类中都这样做了。令我困惑的是 removeAll 是如何返回 true 的,表明 Collection 已经改变,但它没有。我已经坚持了几天了,所以任何提示都将不胜感激。谢谢。
更新:
我一直在尝试使用 Child 哈希码,这似乎是罪魁祸首。如果我根据 id 制作一个简单的哈希码(不好的做法),那么 removeAll 可以工作,但是如果我包含该值,它就会再次停止工作。例如...
// Sample 1: Works with removeAll
int hashCode() {
int hash1 = id.hashCode()
return hash1
}
// Sample 2: Doesn't work with removeAll
int hashCode() {
int hash1 = id.hashCode()
int hash2 = value == null ? 0 : value.hashCode()
return hash1 + hash2
}
// Sample Domain classes (thanks Burt)
class Parent {
static hasMany = [children: Child]
}
class Child {
String name
String value
static constraints = {
value nullable: true
}
}
这种行为是由数据绑定(bind)步骤更新数据,使其变脏来解释的。 (即:child.value.isDirty() == true)这就是我的理解。
首先Grails数据绑定(bind)获取Parent和children,计算每个Child的hashcode。接下来,应用数据更新,这会使 child.value 变脏(如果它改变了),但 Set 的哈希码保持不变。当 removeAll 找到匹配项时,它会使用脏数据构建一个 hashCode,但在 Set 中找不到该 hashcode,因此无法将其删除。本质上,只有当我的所有 hashCode 变量都是干净的时,removeAll 才会起作用。
因此,如果数据必须干净才能删除,一种解决方案是保存两次。像这样...
// Parent Controller
def update(Parent parent) {
parent.children.removeAll{ it.value == null } // Removes CLEAN children with no value
parent.save(flush:true)
parent.refresh() // parent.children is now clean
parent.children.removeAll{ it.value == null } // Removes (formerly dirty) children
parent.save(flush:true) // Success!
}
尽管并不理想,但这很有效。首先,我必须在数据库中允许空值,尽管它们只是短暂存在并且我不想要它们。其次,做两次扑救有点低效。肯定有更好的方法吗?
最佳答案
hashCode
和 equals
奇怪在这里不是问题 - 没有 contains
调用或类似的东西会使用 hashCode
值并可能错过实际数据。如果你看the implementation of removeAll
你可以看到它使用了 Iterator
在每个实例上调用您的闭包并删除任何闭包结果为真的地方,并返回 true
如果至少有一个被删除。使用这个Parent
类(class)
class Parent {
static hasMany = [children: Child]
}
这个
Child
class Child {
String name
String value
static constraints = {
value nullable: true
}
}
以及创建测试实例的代码:
def parent = new Parent()
5.times {
parent.addToChildren(name: 'c' + it)
}
5.times {
parent.addToChildren(name: 'c2' + it, value: 'asd')
}
parent.save()
它为最终的
size()
打印 5 .因此,可能还有其他影响这一点。您不必这样做,但您可以创建自己的 removeAll
做同样的事情,如果你加入一些 println
调用你可能会弄清楚发生了什么:boolean removeAll(collection, Closure remove) {
boolean atLeastOne = false
Iterator iter = collection.iterator()
while (iter.hasNext()) {
def c = iter.next()
if (remove(c)) {
iter.remove()
atLeastOne = true
}
}
atLeastOne
}
调用它作为
println removeAll(parent.children) { it.value == null }
关于grails - Groovy removeAll 闭包不删除 Set 中的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26103913/