简体   繁体   English

Grails:两个域对象之间的多个关系

[英]Grails: multiple relationships between two domain objects

I am trying to implement two different types of relationships between two domain classes in Grails. 我试图在Grails中的两个域类之间实现两种不同类型的关系。

Consider the following; 考虑以下; I have two domain classes, an Author and Book class with an Author having many Books. 我有两个域类,一个作者和书类,作者有很多书。

class Author{           
   String name 
}

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

}

The above depicts a very basic one to many relationship between an Author and a Book. 以上描述了作者和书之间非常基本的一对多关系。 But I also want an Author to have a concept of a list of favourite books. 但我也希望作者有一个喜欢的书籍列表的概念。 This would ideally be represented as a separate one to many relationship describing the same Book object as a list and persisted as such. 理想情况下,这将表示为单独的一对多关系,将同一Book对象描述为列表并保持原样。

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

   static mapping = {
        favouriteBooks joinTable: [name: 'favourite_books',
                key: 'author_id']
   }
}

class Book{
   String title
   static belongsTo = [client:Client]

}

I have tried to describe this as above (among many other methods) and ultimately the database table (favourite_books) is not created. 我试图像上面那样描述这个(在许多其他方法中)并且最终没有创建数据库表(favourite_books)。 I do not get any errors. 我没有得到任何错误。 This is the only way I can think of doing this without using any extra objects which I would like to avoid to keep the model simple. 这是我能想到的唯一方法,不使用任何额外的对象,我希望避免使模型保持简单。 I feel I'm on the right track but maybe missing some vital piece of the puzzle. 我觉得我走在正确的轨道上,但也许错过了一些重要的拼图。

Any help would be much appreciated. 任何帮助将非常感激。

First of all, let's make sure I understand your problem correctly. 首先,让我们确保正确理解您的问题。 You have Book and Author domain classes, but there are two relationships between these classes: 您有BookAuthor域类,但这些类之间有两种关系:

  1. An author writes books, so there's a one-to-many relationship between Author and Book . 作者写书,因此AuthorBook之间存在一对多的关系。 Of course in real life a book may be written by many authors, but it seems in this case we can ignore this. 当然,在现实生活中,许多作者可能会写一本书,但在这种情况下,我们可以忽略这一点。
  2. An author has favourite books, so there's a second many-to-many relationship between Author and Book . 作者有最喜欢的书籍,因此AuthorBook之间存在第二个多对多关系。 This relationship is many-to-many because a particular book could be a favourite of many authors. 这种关系是多对多的,因为一本特定的书可能是许多作者的最爱。

So assuming I've understood the problem correctly, let's try to find a solution. 所以假设我已经正确理解了问题,让我们试着找到一个解决方案。 First of all, let's add the many-to-many relationship (favourite books): 首先,让我们添加多对多关系(最喜欢的书籍):

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

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

Whenever a many-to-many relationship is defined we have to choose one side as being the owner of the relationship. 每当定义多对多关系时,我们必须选择一方作为关系的所有者。 In this case I've specified 在这种情况下,我已经指定

static belongsTo = Author

in the Book class, so Book is the owned side of the relationship and Author is the owner. Book类中,因此Book是关系的所有者,而Author是所有者。 Because of this we should add favourite books to authors rather than vice versa, see here for further details. 因此,我们应该将最喜欢的书籍添加到作者而不是反之亦然, 请参阅此处了解更多详情。

The one-to-many relationship can then be added with: 然后可以添加一对多关系:

class Author {
    String name
    static hasMany = [favourites: Book, booksWritten: Book]
}

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

    Book writtenBy
}

By the way, in your domain model you included the following in the Author class 顺便说一句,在您的域模型中,您在Author类中包含以下内容

static mapping = {
    favouriteBooks joinTable: [name: 'favourite_books', key: 'author_id']
}

This will cause the join table to be named instead favourite_books , whereas in my model the join table will default to author_favourites . 这将导致连接表被命名为favourite_books ,而在我的模型中,连接表将默认为author_favourites If for some reason you particularly want the join table to be named like this (eg you're trying to map the classes to existing tables), then feel free to include the above. 如果由于某种原因你特别想要将连接表命名为这样(例如,您正在尝试将类映射到现有表),那么请随意包含上述内容。

Finally, if you find yourself struggling with defining domain class mappings, and are more comfortable with creating the tables, then generating the domain classes from them, check out this plugin 最后,如果您发现自己正在努力定义域类映射,并且更熟悉创建表,然后从它们生成域类,请查看此插件

Finally figured this out. 终于搞清楚了。 Thanks to Don for pointing me in the direction of the db-reverse-engineer plugin which helped expose the key property that allows for this mapping strategy. 感谢Don让我指向db-reverse-engineer插件的方向,这有助于公开允许这种映射策略的关键属性。 Basically it all came down to using GORM's mappedBy association setting to explicitly tell Grails how the multiple hasMany references should be mapped. 基本上,所有这些都归结为使用GORM的mappedBy关联设置来明确告诉Grails如何映射多个hasMany引用。 The class files that worked are as follows: 有效的类文件如下:

class Author {

    String name
    static hasMany = [books: Book, favourites: Book]

    // need to disambiguate the multiple hasMany references with the 
    // 'mappedBy' property:
    static mappedBy =   [books: "author",
                        favourites: "authors"]
}

class Book {

    String title
    Author author

    static hasMany = [authors: Author]
    static belongsTo = [Author]
}

Thanks again for the help 再次感谢您的帮助

Modify Book domain class. 修改Book域类。 Remove author mapping. 删除author映射。

class Book{
   String title
   static belongsTo = [Author]
}

Look for the new table FAVORITE_BOOKS once clean and run-app . 一旦cleanrun-app查找新表FAVORITE_BOOKS。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM