2011-07-01 60 views
1

我有2個由多對多關係映射的域類。我遵循Grails文檔的說明,但在處理這些域上的數據時仍然遇到一些問題。這裏是我的2域類:Grails多對多關係的動態查找器

class User { 
    String name 
    int age 
    String job 
    static hasMany = [groups : Group] 
    static belongsTo = [org : Organization] 
} 

class Group { 
    String groupName 
    String code 
    static hasMany = [members : User] 
} 

我的問題是:
1.上述關係需要一個類持有屬於關聯是關係的「所有者」。在這種情況下,用戶屬於Group,但我不知道如何將belongsTo設置爲User類,因爲Grails建議的標準語法是static belongsTo = [Group](只需指定所有者類名),所以我不能:
- 把它放入存在屬於關聯這樣的:靜態屬於關聯= [ORG:組織,組]
- 或定義另一個屬於關聯這樣的:靜態屬於關聯= [組]

  • 是例如右下方:

    類Book { 字符串標題 靜態屬於關聯=作者 靜態的hasMany = [作者:作者簡介]

    static mapping = { 
        authors joinTable:[name:"mm_author_books", key:'mm_book_id' ] 
    } 
    

    } 類作者{ 字符串名稱 靜態的hasMany = [書:書]

    static mapping = { 
        books joinTable:[name:"mm_author_books", key:'mm_author_id'] 
    } 
    

    }

  • (參考鏈接:Many-to-Many link tables in grails (GORM)/hibernate
    我的意思是,我們需要指定的名稱爲每個類的連接表的eign鍵?

    1. 如果我想查找所有名爲「ABC」的指定組的成員的用戶,我該如何使用Grails的DynamicFinder?

    謝謝你這麼多

    回答

    4

    m2m關係非常罕見,所以我一直覺得奇怪的是必須指定一個讓GORM正常工作。正因爲如此,我不這樣做。我將連接表創建爲一個域。然後事情得到真的簡單。

    class UserGroup implements Serializable { 
    
        User user 
        Group group 
    
        boolean equals(other) { 
         if (!(other instanceof UserGroup)) { 
          return false 
         } 
    
         other.user?.id == user?.id && 
          other.group?.id == group?.id 
        } 
    
        int hashCode() { 
         def builder = new HashCodeBuilder() 
         if (user) builder.append(user.id) 
         if (group) builder.append(group.id) 
         builder.toHashCode() 
        } 
    
        static UserGroup get(long userId, long groupId) { 
         find 'from UserGroup where user.id=:userId and group.id=:groupId', 
          [userId: userId, groupId: groupId] 
        } 
    
        static UserGroup create(User user, Group group, boolean flush = false) { 
         new UserGroup(user: user, group: group).save(flush: flush, insert: true) 
        } 
    
        static boolean remove(User user, Group group, boolean flush = false) { 
         UserGroup instance = UserGroup.findByUserAndGroup(user, group) 
         instance ? instance.delete(flush: flush) : false 
        } 
    
        static void removeAll(User user) { 
         executeUpdate 'DELETE FROM UserGroup WHERE user=:user', [user: user] 
        } 
    
        static void removeAll(Group group) { 
         executeUpdate 'DELETE FROM UserGroup WHERE group=:group', [group: group] 
        } 
    
        static mapping = { 
         id composite: ['group', 'user'] 
         version false 
        } 
    } 
    

    然後你只需要在你的User和Group類中創建getters。您將不會在任何一個班級中擁有User用戶或Group組。沒有必要將它們與hasMany/belongsTo進行映射,因爲所做的只是創建連接表,這通過創建UserGroup域來完成。

    class User { 
        Set<Group> getGroups() { 
        UserGroup.findAllByUser(this).collect { it.group } as Set 
        } 
    } 
    
    class Group { 
        Set<User> getUsers() { 
        UserGroup.findAllByGroup(this).collect { it.user } as Set 
        } 
    } 
    

    一旦你在的地方,這些你可以使用你的用戶組域中創建的方法和/或可以在其上使用的發現者......

    def userGroupInstance = UserGroup.findByUserAndGroup(userInstance, groupInstance) 
    def userGroups = UserGroup.findAllByUser(userInstance) 
    def userGroupInstance = UserGroup.get(userId, groupId) 
    

    你的想法。這presentation by Burt Beckwith揭示了爲什麼這是一個很好的方法,以及一些其他偉大的技巧提高性能更多的亮點。

    0
    1. belongsTo將創建另一個M:1間的關係(場) - 你告訴我們,如果有一個「羣主」在你的情況下User。如果我只希望強制執行至少一個組,我會爲User.groups定製驗證程序,並檢查它是否爲空。 (我不確定) - 我相信是,如果密鑰名稱不同於默認的Hibernat/GORM「userId」/「groupId」。

    2. findBy*()方法不會在這裏工作,你需要一個CriteriaBuilder,像here