2014-09-29 136 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

相關問題