2014-09-29 48 views
0

我正在使用Grails 2.3.7中的父/子关系进行数据绑定,并且在删除时遇到问题。该表单有许多可选的子项,为了保持数据库的整洁,我想清除空白值(空值)。我发现了一些很好的文章,建议使用removeAll来过滤我的条目,但我无法删除或removeAll工作!Groovy removeAll闭合不会删除集合中的对象

例如......(家长有10个孩子,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已经改变,但它没有改变。我已经坚持了几天,所以任何提示将不胜感激。谢谢。

更新:

我一直在尝试与孩子哈希码,这似乎是罪魁祸首。如果我根据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 
    } 
} 

此行为通过数据绑定步骤更新数据来解释,使其变脏。 (即:child.value.isDirty()== true)这是我的理解。

第一次Grails数据绑定获取父和孩子,并计算每个孩子的哈希码。接下来,应用数据更新使child.value变脏(如果变化),但Set的hashcode保持不变。当removeAll发现匹配时,它会使用脏数据构建一个hashCode,但是在Set中找不到该哈希码,因此无法删除它。基本上,removeAll只会在我的所有hashCode变量都干净时才起作用。

因此,如果数据必须干净才能删除它,一种解决方案是将其保存两次。像这样...

// 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! 
} 

虽然这并不理想,但它可以工作。首先,我必须在数据库中允许空值,尽管它们只是短暂存在,我不想要它们。其次,做两次保存有点低效。当然必须有更好的方法?

+0

你是怎么得到的,如果你打印孩子之前和之后removeAll出来? – injecteer 2014-09-29 16:15:24

+0

请发布您的'''父'''类 – Victor 2014-09-29 16:17:37

+0

您可以尝试:'parent.children.findAll {it.value == null} *。removeFromParent(parent)' – 2014-09-29 16:25:55

回答

1

hashCodeequals怪事是不是一个问题在这里 - 有没有contains来电或类似的东西,将使用hashCode价值和潜在错过了实际数据。如果您查看the implementation of removeAll,您可以看到它使用Iterator在每个实例上调用您的闭包,并删除闭包结果为真的地方,如果至少有一个被删除,则返回true。使用这种Parent

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() 

它打印5的最后size()。所以这可能还有其他影响。你不应该有,但你可以创建自己的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 } 
+0

我无法解释它,但在数据绑定期间为每个子对象调用hashCode(),以及在removeAll中删除每个对象。我试过你的自定义removeAll和Child.hashCode()在“iter.remove()”上调用。结果与removeAll相同,它返回true并且集合不变。我已经更新了我的问题,并提供了一个简单的解决方法。 – Vimm 2014-09-30 17:58:06

相关问题