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

私の問題は次
のとおりです。このコンテキストでは、User は Group に属していますが、Grails が提案する標準的な構文は static membersTo = [Group] (所有者クラス名を指定するだけ) であるため、属するクラスを User クラスに配置する方法がわかりません。できません:
- 次のように既存の属しているに入れます: static belongsTo = [org : Organization, Group]
- または、次のように別の属しを定義します: static belongsTo = [Group]

  1. 右の例の下にあります:

    class Book { 文字列のタイトル 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']
    }
    

    }

(参照リンク: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 を作成するだけです。どちらのクラスにもユーザー ユーザーまたはグループ グループはありません。それらを 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 によるこのプレゼンテーションでは、パフォーマンスを向上させるためのその他の優れたヒントとともに、これが優れたアプローチである理由を詳しく説明しています。

于 2011-07-01T13:43:14.883 に答える
0
  1. belongsTo別のM:1関係(フィールド)を作成します-あなたの場合に「メイングループ」があるかどうかがわかりUserます。少なくとも 1 つのグループだけを強制したい場合は、User.groupsそれが空でないことを確認するためにカスタム バリデーターを使用します。

  2. (ここではよくわかりません) - キー名がデフォルトの Hibernat/GORM " userId"/" groupId" と異なる場合は、イエスだと思います。

  3. findBy*()メソッドはここでは機能しません。ここのような CriteriaBuilder が必要です。

于 2011-07-01T09:10:57.257 に答える