Несколько связей hasMany с одним и тем же классом домена в Grails - PullRequest
7 голосов
/ 24 сентября 2011

Я использую Grails, и у меня есть модель домена с несколькими атрибутами hasMany для одного и того же класса домена, которая выглядит следующим образом:

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

Проблема, с которой я сталкиваюсь, заключается в том, что когдаЯ добавляю что-то в список постов, он также каким-то образом превращается в списки лайков и антипатий.По крайней мере, так выглядит, когда я перебираю каждый из этих списков.

Я думаю, что проблема в том, что у меня также есть следующие отношения в моем почтовом домене:

static belongsTo = [ contributer : Contributer ]

Чтонаилучший способ настроить эти отношения, чтобы моя модель работала?Любые предложения?


@ Wayne,

Я также пытался использовать ваш тест, и он успешно прошел.Итак, единственное, о чем я могу думать, это то, что с моим методом сохранения в моем PostController что-то не так.Я вставил соответствующий код ниже (я использую плагин 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 ]

11 голосов
/ 26 сентября 2011

Проблема в том, что у вас есть один ко многим между постом и автором (у поста есть автор, у автора много постов), а также два ко многим отношениям между постом и спонсором (пост имеет много симпатий, лайков как много постов) (в посте много недолюбливателей, не нравится многим постам).belongsTo в Посте объясняет поведение, но его удаление не решит проблему, просто создайте другие.Конечный результат состоит в том, что соглашения GORM будут терпеть неудачу, поэтому вы должны сообщить GORM, как вести себя или моделировать вещи по-разному.

Есть несколько вариантов, но на ум приходит смоделировать модель голосования отдельно отРазместите и сделайте так, чтобы участник hasMany likeVotes и hasMany dislikeVotes

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 смоделировал это как одну таблицу голосования со столбцом дискриминатора для разделения симпатий и антипатий;это позволит вам устранить конфликты между лайками, антипатиями и авторскими постами.

Затем в Contributor

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

Отношения теперь прояснены:

  1. У поста много лайковВсего*
  2. У участника есть много лайков.
  3. У пользователя много диско голосов.
  4. У поста есть один участник.
  5. Автор имеет много сообщений.эти отношения и будут вести себя соответственно.

    Если вам не нравится эта опция, следующим шагом будет указать пользовательские сопоставления для вашей структуры базы данных, а затем использовать mappedBy для разграничения различных связей.Это подход, который нужно использовать, если вы абсолютно хотите, чтобы Участник напрямую связывался с Post тремя различными способами.

5 голосов
/ 13 ноября 2013

Используйте 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

   ... 
}
4 голосов
/ 02 августа 2012

Хотя стандартным способом для multi-M: M является использование joinTable , как рекомендовано в GRAILS-4884 .

1 голос
/ 15 мая 2013

Это должно работать:

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']
}
1 голос
/ 24 сентября 2011

Попробуйте переключиться на отношение «многие ко многим» и определить класс домена сопоставления. В этом классе сопоставления доменов вы можете указать тип отношения; нравится, не нравится, или автор.

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 для получения дополнительной информации о классе домена сопоставления многие-ко-многим.

1 голос
/ 24 сентября 2011

Можете ли вы показать тест, который не прошел?Я положил то, что я считаю вашим делом, в проект 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)

}

...