2015-11-07 77 views
0

鑑於以下兩個領域:的Grails GORM約束

class Follows { 
    User followee 
    ... 
    static belongsTo = [follower: User] 
} 

class User { 
    String name 
    String lastName 
    ... 
    static hasMany = [ follows: Follows ] 
    static mappedBy = [ follows: 'follower' ] 
} 

它創建如下表:

+------+-------------+-------------+ 
| id | follower_id | followee_id | 
+------+-------------+-------------+ 
| 1 | 1   | 3   | 
| 2 | 3   | 2   | 
| 3 | 2   | 1   | 
+------+-------------+-------------+ 

是否有通過約束上辦法阻止跟隨的副本 - 關注者?我正在試圖防止兩個方向,比如,用戶ID 3應該不能遵循用戶ID 1如果用戶ID 1已經按照用戶ID 3.

換句話說,這是我正在試圖防止:

+------+-------------+-------------+ 
| id | follower_id | followee_id | 
+------+-------------+-------------+ 
| 1 | 1   | 3   | 
| 2 | 3   | 1   | 
+------+-------------+-------------+ 

我知道,我也許可以在插入之前查詢數據庫來檢查,如果用戶1是繼3(或者反過來),如果真的取消插入,但我試圖避免按按照的操作打兩次DB。

乾杯和感謝您的所有答案!

回答

0

不,沒有現有的約束來處理這種情況。你可以創建自己的約束,但它必須查詢數據庫,所以沒有意義。

但是,如果您向Follows添加包含適用於以下兩個方向的唯一值的新屬性,那麼您可以使用的唯一約束。

class Follows { 
    User followee 
    ... 
    Integer someUniqueProperty 

    static belongsTo = [follower: User] 

    static constraints = { 
     someUniqueProperty unique: true 
    } 

    def beforeInsert() { 
     someUniqueProperty = calculateUniqueProperty() 
    } 

    def beforeUpdate() { 
     someUniqueProperty = calculateUniqueProperty() 
    } 

    private Integer calculateUniqueProperty() { 
     [follower.id, followee.id].sort().hashCode() 
    } 
} 

在上面的例子中,someUniqueProperty必須跨越的Follows所有實例是唯一的。在插入/更新實例之前,通過將follower和​​放入列表中,始終以相同的順序,然後獲取哈希碼來設置其值。這是基於以下事實:[1, 3].hashCode() == [3, 1].sort().hashCode()

簡而言之,添加一個唯一屬性允許數據庫強制執行所需的約束。

+0

儘管像約束用法這樣更優雅的解決方案會非常棒,但您的解決方案非常簡單明瞭。真棒回答!乾杯! – mradzinski

+0

不客氣。順便說一句,我的解決方案確實使用約束看例子中的約束閉包。 –

+0

是的,我指的是一個簡單的約束,以防止在兩個方向重複,而不是使用散列。順便說一句,我測試了它,它完美的作品。 – mradzinski