【问题标题】:Multiple hasMany relationships to same domain class in GrailsGrails中与同一个域类的多个hasMany关系
【发布时间】:2011-09-24 02:48:28
【问题描述】:

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

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

我遇到的问题是,当我将某些内容添加到帖子列表时,它也会以某种方式进入喜欢和不喜欢列表。至少,当我遍历每个列表时,它看起来是这样的。

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

static belongsTo = [ contributer : Contributer ]

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


@韦恩,

我也尝试过使用您的测试,并且成功通过了。所以,我唯一能想到的就是我的 PostController 中的保存方法有问题。我已经粘贴了下面的相关代码(我使用的是 Spring Security Core 插件,我的 Contribute 类扩展了使用该插件创建的 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])
}
}

这里有什么突出的吗?

【问题讨论】:

  • 当您向贡献者添加帖子时,您是执行“myPost.contributer=myContribute”还是“myContributer.addToPosts(myPost)”?
  • @fixitaagain,感谢您的回复。两种方法我都试过了,结果一样。

标签: grails grails-orm has-many


【解决方案1】:

问题是 Post 和 Contributor 之间存在一对多关系(帖子有作者,作者有很多帖子)以及 Post 和 Contributor 之间存在两个多对多关系(帖子有很多喜欢者,喜欢者喜欢很多帖子)(帖子有很多不喜欢的人,不喜欢的人不喜欢很多帖子)。 Post 中的 belongsTo 确实解释了该行为,但删除它并不能解决问题,只是创建不同的问题。最终结果是 GORM 约定将达不到要求,因此您必须告诉 GORM 如何以不同的方式表现或建模。

有多种选择,但首先想到的是将 Vote 与 Post 分开建模,并使其成为贡献者 hasManylikeVotes 和 hasManydislikeVotes

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. 帖子有很多赞
  2. 帖子有很多不喜欢的投票
  3. 投稿人有很多赞
  4. 投稿人有很多不喜欢的投票
  5. 帖子只有一位贡献者
  6. 贡献者有很多帖子

GORM 可以理解这些关系并会采取适当的行动。

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

【讨论】:

  • 感谢您的回答!我认为这消除了很多关于 GORM 的困惑。信息量很大!
  • 类型不再相同,但它们应该相同。这可能会产生不良副作用。
【解决方案2】:

在您的域类中使用 static mappedBy

例如:

在多方域对象中(Contribter.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

   ... 
}

【讨论】:

    【解决方案3】:

    不过,多 M:M 的标准方法是使用 joinTable,正如 GRAILS-4884 中所推荐的那样。

    【讨论】:

      【解决方案4】:

      你能展示失败的测试用例吗?我将我认为的情况放入 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)
      

      }

      【讨论】:

        【解决方案5】:

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

        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,了解有关多对多映射域类的更多信息。

        【讨论】:

          【解决方案6】:

          这应该可行:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-03-26
            • 1970-01-01
            • 1970-01-01
            • 2015-12-28
            • 1970-01-01
            • 1970-01-01
            • 2014-04-02
            • 2013-05-20
            相关资源
            最近更新 更多