3

我有 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属于Group,但我不知道如何将belongsTo放到User类中,因为Grails建议的标准语法是static belongsTo = [Group](只需指定所有者类名),所以我不能:
- 像这样将其放入存在的 belongsTo 中:static belongsTo = [org : Organization, Group]
- 或者像这样定义另一个 belongsTo:static belongsTo = [Group]

  1. 下面的例子是正确的:

    class Book { String title static belongsTo = Author static hasMany = [authors:Author]

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

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

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

    }

(参考链接:grails (GORM) / hibernate 中的多对多链接表
我的意思是我们是否需要为每个类指定连接表的外键名称?

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

非常感谢

4

2 回答 2

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。任何一个类中都没有 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)

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

于 2011-07-01T13:43:14.883 回答
0
  1. belongsToUser将创建另一个 M:1 关系(字段)-您告诉 a在您的情况下是否存在“主要组” 。如果我只想强制执行至少一个组,我会使用自定义验证器来User.groups检查它是否为空。

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

  3. findBy*()方法在这里不起作用,你需要一个 CriteriaBuilder,就像这里一样。

于 2011-07-01T09:10:57.257 回答