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

发布于 2024-11-18 04:14:46 字数 1273 浏览 2 评论 0原文

我有 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建议的标准语法是staticbelongsTo = [Group](只需指定所有者类名),所以我不能:
- 将其放入现有的 ownsTo 中,如下所示: static ownTo = [org : Organization, Group]
- 或像这样定义另一个belongsTo: static ownTo = [Group]

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

    类书{ 字符串标题 静态属于=作者 静态 hasMany = [作者:作者]

    静态映射 = {
        作者 joinTable:[name:"mm_author_books", key:'mm_book_id' ]
    }
    

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

    静态映射 = {
        书籍 joinTable:[name:"mm_author_books", key:'mm_author_id']
    }
    

    }

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

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

太感谢了

I have 2 domain classes which are mapped by many-to-many relationship. I followed the instruction of Grails documentation, but I still have some problem when processing data on those domains. Here are my 2 domain classes:

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]
}

My problems are:
1. The above relationship require one class hold belongsTo to be the "owner" of the relationship. In this context, the User belongs to the Group, but I do not know how to put the belongsTo to User class, because the standard syntax that Grails suggest is static belongsTo = [Group] (just specify the owner class name), so I cannot:
- put it into the exist belongsTo like this: static belongsTo = [org : Organization, Group]
- or define another belongsTo like this: static belongsTo = [Group]

  1. Is below example right:

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

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

    }
    class Author {
    String name
    static hasMany = [books:Book]

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

    }

(Ref link: Many-to-Many link tables in grails (GORM) / hibernate)
I mean that do we need to specify the name of foreign key of the join table for each class?

  1. If I want to find all User that are members of a specified Group whose name is "ABC", how can I use the DynamicFinder of Grails?

Thank you so much

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

梦中的蝴蝶 2024-11-25 04:14:46

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
  }
}

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

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

你明白了。 Burt Beckwith 的演示 进一步阐明了为什么这是一个很好的方法以及其他一些方法提高性能的好技巧。

It is very rare that m2m relationships have an owning side, so I've always found it odd to have to specify one for GORM to work correctly. Because of this, I don't do it this way. I create the join table as a domain. Then things get really simple.

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
    }
}

Then you just need to create the getters in your User and Group class. You won't have User user or Group group in either class. There is no need to map them with hasMany/belongsTo because all that will do is create the join table, which you've done by creating the UserGroup domain.

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
  }
}

Once you have these in place you can use the methods you created in the UserGroup domain and/or you can use finders on it...

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

You get the idea. This presentation by Burt Beckwith sheds more light on why this is a good approach along with some other great tips for performance increases.

触ぅ动初心 2024-11-25 04:14:46
  1. belongsTo 将创建另一个 M:1 关系(字段) - 您可以判断您的案例中的 User 是否存在“主组”。如果我只想强制执行至少一个组,我会使用自定义验证器来检查 User.groups 是否为空。

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

  3. findBy*() 方法在这里不起作用,您需要一个 CriteriaBuilder,例如 此处

  1. belongsTo will create another M:1 relationship (field) - you tell if there is a "main group" for a User in your case. If I wished only to enforce at least one group, I'd go with a custom validator for User.groups checking it's not empty.

  2. (I'm not sure here) - I believe yes, if the key name differs from default Hibernat/GORM "userId"/"groupId".

  3. findBy*() methods won't work here, you need a CriteriaBuilder, like here.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文