具有Grails多对多关系的动态查找器

时间:2011-07-01 08:47:29

标签: grails many-to-many dynamic-finders

我有2个域类,它们通过多对多关系映射。我按照Grails文档的说明进行操作,但在处理这些域上的数据时仍然存在一些问题。这是我的2个域类:

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.上述关系要求一个类持有属于该关系的“所有者”。在这种情况下,用户属于组,但我不知道如何将belongsTo放到User类,因为Grails建议的标准语法是static belongsTo = [Group](只是指定所有者类名),所以我不能:
- 将它放入存在的belongsTo中:static belongsTo = [org:Organization,Group]
- 或者像这样定义另一个belongsTo:static belongsTo = [Group]

  1. 以下示例正确:

    class Book {     字符串标题     static belongsTo =作者     static hasMany = [作者:作者]

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

    } 类作者{     字符串名称     static hasMany = [books:Book]

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

    }

  2. (参考链接:Many-to-Many link tables in grails (GORM) / hibernate
    我的意思是我们是否需要为每个类指定连接表的外键名称?

    1. 如果我想查找属于名称为“ABC”的指定组成员的所有用户,我该如何使用Grails的DynamicFinder?
    2. 非常感谢

2 个答案:

答案 0 :(得分:6)

很少有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类中创建getter。您不会在任何一个类中拥有用户用户或组。不需要使用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
  }
}

一旦你有了这些,你可以使用你在UserGroup域中创建的方法和/或你可以使用它上面的查找器......

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

你明白了。这个presentation by Burt Beckwith更清楚地说明了为什么这是一个好的方法以及其他一些提高性能的好方法。

答案 1 :(得分:0)

  1. belongsTo将创建另一个M:1关系(字段) - 您可以判断在您的情况下是否存在User的“主要群组”。如果我只希望强制执行至少一个组,我会使用自定义验证器User.groups检查它是否为空。

  2. (我不确定) - 我相信是的,如果密钥名称与默认的Hibernat / GORM“userId”/“groupId”不同。

    < / LI>
  3. findBy*()方法在这里不起作用,你需要一个CriteriaBuilder,比如here