【问题标题】:Grails: How to insert with many-to-many with extra column?Grails:如何插入带有额外列的多对多?
【发布时间】:2016-02-19 16:58:23
【问题描述】:

authorbook 和连接表author_books 和额外的royalty 列为例:

CREATE TABLE 'author_books' (
    'author_id` bigint(20) NOT NULL,
    'book_id' bigint(20) NOT NULL,
    'royalty' int NOT NULL,
    PRIMARY KEY ('author_id', 'book_id') ,
    INDEX 'FK24C812F6183CFE1B' ('book_id'),
    INDEX 'FK24C812F6DAE0A69B' ('author_id')

)

如果我没有 db-reverse-engineer 插件生成 AuthorBooks 类,生成的代码将是:

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

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

以下代码:

def author1 = new Author(name: 'author1').addToBooks(new Book(title: 
                         'book1')).save(flush: true)

将在author 表中插入一行,在book 表中插入一行,但无法插入author_books,因为royalty 不能为空。

但是,如果让 db-reverse-engineer 插件生成 AuthorBooks 类,生成的代码将是:

class Author {
    String name
    static hasMany = [authorBookses: AuthorBooks]
}

class Book {
    String title
    static hasMany = [authorBookses: AuthorBooks]
}

class AuthorBooks implements Serializable {
    Long authorId
    Long bookId
    Integer royalty
    Author author
    Book book

    int hashCode() {
        def builder = new HashCodeBuilder()
        builder.append authorId
        builder.append bookId
        builder.toHashCode()
    }

    boolean equals(other) {
        if (other == null) return false
        def builder = new EqualsBuilder()
        builder.append authorId, other.authorId
        builder.append bookId, other.bookId
        builder.isEquals()
    }

    static belongsTo = [author: Author, book: Book]

    static mapping = {
        author insertable: false       // these insertable and updateable codes were manually added
        author updateable: false       // otherwise it would not run
        book insertable: false
        book updateable: false
        id composite: ["authorId", "bookId"]
        version false
   }
}

在这种情况下,我不能调用author.addToAuthorBooks(new AuthorBooks( )),因为author_books 不能让author_idbook_id 成为null。最后,我需要执行以下操作才能使其正常工作:

def author1 = new Author(name: 'author1').save(flush: true)
def book1 = new Book(title: 'book1').save(flush: true)
def authorbook1 = new AuthorBooks(authorId: author1.id, bookId: book1.id, 
                      royalty: 50, author: author1, book: book1).save(flush: true)

这对我来说是可以接受的。但是,在 Author 和 Book 类中拥有 hasMany 关联有什么好处呢?有没有更好的方法来做到这一点?理想情况下,像关注这样的东西会很酷

def author1 = new Author(name: 'author1').addToBooks(book: new Book(title: 'book1'), 
                         royalty: 50).save(flush: true)

【问题讨论】:

    标签: grails many-to-many grails-orm


    【解决方案1】:

    我想推荐一些更改,特别是在您的 AuthorBooks 域中:

    class Author {
        String name
        static hasMany = [authorBookses: AuthorBooks]
    }
    
    class Book {
        String title
        static hasMany = [authorBookses: AuthorBooks]
    }
    
    class AuthorBooks implements Serializable {
        Integer royalty
        Author author
        Book book
    
        int hashCode() {
            def builder = new HashCodeBuilder()
            builder.append author.id
            builder.append book.id
            builder.toHashCode()
        }
    
        boolean equals(other) {
            if (other == null) return false
            def builder = new EqualsBuilder()
            builder.append author.id, other.author.id
            builder.append book.id, other.book.id
            builder.isEquals()
        }
    
        static belongsTo = [author: Author, book: Book]
    
        static mapping = {
            id composite: ["author", "book"]
            version false
       }
    }
    

    为书籍和作者添加额外的 ID 是多余的。我不能 100% 确定我会建议什么,但值得尝试以下方法:

    def author1 = new Author(name: 'author1', authorBookses: new HashSet())
    def book1 = new Book(title: 'book1', authorBookses: new HashSet())
    def authorbook1 = new AuthorBooks(royalty: 50, author: author1, book: book1)
    
    author1.authorBookses(authorbook1)
    book1.authorBookses(authorbook1)
    
    authorbook1.save(flush: true)
    

    【讨论】:

    • 这似乎是正确的方法。以下是稍作修改的代码:
    • 这似乎是正确的方法。 (代码需要一些语法更改:new AuthorBooks( ) 没有 authorIdbookId 参数;并且author1book1 都调用 addToAuthorBooks(authorbook1) 而不是 authorBookses(authorbook1))。但是调用authorbook1.save(flush: true) 会导致ERROR context.GrailsContextLoaderListener - Error initializing the application: null。似乎save() 调用导致了 NPE。
    • 是的,我忽略了这一点。更新了答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-07-13
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多