与Grails中的同一域类有多个hasMany关系

时间:2011-09-24 02:48:29

标签: grails gorm has-many

我正在使用Grails,并且我有一个具有多个hasMany属性的域模型到同一个域类,如下所示:

static hasMany = [ posts : Post, likes : Post, dislikes : Post ]

我遇到的问题是,当我在帖子列表中添加内容时,它也会以某种方式将其变成喜欢和不喜欢的列表。至少,当我遍历每个列表时,它就是这样。

我认为问题是我在Post域中也有以下关系:

static belongsTo = [ contributer : Contributer ]

配置这些关系以使我的模型有效的最佳方法是什么?有什么建议吗?


@Wayne,

我也试过使用你的测试,并成功通过了。所以,我唯一能想到的是我的PostController中的save方法有问题。我已粘贴下面的相关代码(我使用的是Spring Security Core插件,而我的Contributer类扩展了使用该插件创建的User类):

@Secured(['IS_AUTHENTICATED_FULLY'])
def save = {
def props = [title:params.title, post:params.post,   category:Category.get(params.category.id)]

def user = Contributer.get(springSecurityService.principal.id)
def postInstance = new Post(props)

postInstance.contributer = user
if (postInstance.save(flush: true)) {
  flash.message = "${message(code: 'default.created.message', args: [message(code: 'post.label', default: 'Post'), postInstance.id])}"
  redirect(action: "show", id: postInstance.id)
}
else {
  render(view: "create", model: [postInstance: postInstance])
}
}

这里有什么突出的吗?

6 个答案:

答案 0 :(得分:11)

问题在于Post和Contributor之间有一对多(帖子有作者,作者有很多帖子)以及Post和Contributor之间有两对多关系(帖子有很多喜欢的帖子,像很多帖子一样)(帖子有很多不喜欢的人,不喜欢很多帖子)。 Post中的belongsTo确实解释了行为,但删除它不会解决问题,只需创建不同的问题。最终的结果是GORM约定将会失败,所以你必须告诉GORM如何对事物进行不同的行为或建模。

有几个选项,但跳出来的那个选项是将模型投票与Post分开建模并使其成为贡献者hasMany喜欢投票和hasMany不喜欢投票

class Vote {

   // for illustration here, you need to think about the 
   // cascading behavior that makes sense and model it if you decide 
   // to go this route. 
  belongsTo = [post, contributor] 

}

class LikeVote extends Vote {
}

class DislikeVote extends Vote {
}

GORM会将此模型建模为一个带有鉴别器列的投票表,以区分好恶;这样可以消除喜欢,不喜欢和创作帖子之间的冲突。

然后在贡献者

 hasMany = [likes:LikeVote, dislikes:DislikeVote, posts:Post]

现在关系清理了:

  1. Post有许多喜欢投票
  2. Post有很多不喜欢的投票
  3. 贡献者有许多喜欢投票
  4. 贡献者有很多不喜欢的投票
  5. Post有一位撰稿人
  6. 投稿人有很多帖子
  7. GORM可以理解这些关系并且行为恰当。

    如果您不喜欢此选项,则下一步是为数据库结构指定自定义映射,然后使用mappedBy区分各种关系。如果您绝对希望让投稿人以三种不同的方式直接与Post相关,那么这就是您要采取的方法。

答案 1 :(得分:5)

在您的域类

中使用 static mappedBy

例如:

在许多辅助域名对象( Contributer.groovy )中:

static hasMany = [ posts : Post, likes : Post, dislikes : Post ]
static mappedBy = [posts: "postsContributer", likes: "likesContributer", dislikes: "dislikesContributer"]

在一个侧域对象( Post.groovy )中:

Class Post {

       static belongsTo = [ contributer : Contributer ]

       Contributer postsContributer
       Contributer likesContributer
       Contributer dislikesContributer

   ... 
}

答案 2 :(得分:4)

尽管如此,多个M:M的标准方法是joinTable使用GRAILS-4884

答案 3 :(得分:1)

您能否显示失败的测试用例?我把我认为的内容放到了grails 1.3.7项目中,测试通过了:

class Post {
    String text ="postal"
    static belongsTo = [ contributor : Contributor ]
    static constraints = { }
}
class Contributor {
    String name = "Big C"
    static hasMany = [ posts : Post, likes : Post, dislikes : Post ]
    static constraints = { }
}

// integration test
void testMultipleRel() {
    Contributor c = new Contributor().save()
    assertNotNull c

    Post p1 = new Post(text:"neutral")
    Post p2 = new Post(text:"like")
    Post p3 = new Post(text:"dislike")
    [p1,p2,p3].each {c.addToPosts(it).save()}
    assertNotNull p1
    assertNotNull p2
    assertNotNull p3

    assertNull c.likes
    assertNull c.dislikes

    c.addToLikes(p2)
    c.addToDislikes(p3)

    assertEquals ([p1, p2, p3] as Set, c.posts as Set)
    assertEquals ([p2]         as Set, c.likes as Set)
    assertEquals ([p3]         as Set, c.dislikes as Set)

}

答案 4 :(得分:1)

尝试切换到多对多关系并定义映射域类。在此映射域类中,您可以指定关系类型;喜欢,不喜欢或作者。

class Contributor {
    static hasMany = [contributorPosts:ContributorPost]
}

class ContributorPost {
    Post post
    Contributor contributor
    Boolean like
    Boolean dislike
    Boolean author
}

class Post {
    static hasMany = [contributorPosts:ContributorPost]
}

您可以在此处http://www.grails.org/Many-to-Many+Mapping+without+Hibernate+XML查看有关多对多映射域类的详细信息。

答案 5 :(得分:1)

这应该有效:

static hasMany = [ posts : Post, likes : Post, dislikes : Post ]

static mapping = {
    posts joinTable: [name: 'contributor_posts']
    likes joinTable: [name: 'contributor_likes']
    dislikes joinTable: [name: 'contributor_dislikes']
}