Hibernate 如何配置Grails gorm save以不获取所有关联?

Hibernate 如何配置Grails gorm save以不获取所有关联?,hibernate,grails,gorm,Hibernate,Grails,Gorm,我正在使用Grails2.5.4 我注意到,如果调用域对象的save(),Grails会尝试逐个获取对象的所有关联。例如,设置如下: class Person { String name static hasMany = [comments: Comment] } 当我运行这样的代码时: Person p = Person.get(1234) p.save() 看看hibernate日志,我看到在实际更新p之前,Grails尝试获取与p相关的每个注释,每个注释一个查询

我正在使用Grails2.5.4


我注意到,如果调用域对象的save(),Grails会尝试逐个获取对象的所有关联。例如,设置如下:

class Person {
    String name 

    static hasMany = [comments: Comment] 
}
当我运行这样的代码时:

Person p = Person.get(1234)
p.save() 
看看hibernate日志,我看到在实际更新p之前,Grails尝试获取与p相关的每个注释,每个注释一个查询,并且保存的性能非常糟糕,即使我尝试做的只是更新p的地址

是否有任何方法可以配置域对象,以便save()忽略关联,因为很明显,我将只使用自己的保存服务保存注释(类似于
commentService.addComment(params)
),并且在更新Person时从不保存注释

我不想在找人的时候急切地获取评论。我知道这可以解决延迟加载问题,但这并不理想。我所要做的就是更新Person对象上的一些字段值,同时完全忽略任何映射的关联。因此,没有理由获取关联

看看hibernate日志,我看到在实际更新p之前, Grails尝试获取与p关联的每个注释,每个注释一个查询 注释,则保存的性能非常糟糕

我无法复制这一点。请参阅上的项目

Comment.groovy

// grails-app/domain/demo/Comment.groovy
package demo

class Comment {
    String text
}
// grails-app/domain/demo/Person.groovy
package demo

class Person {
    String name
    static hasMany = [comments: Comment]
}
// grails-app/conf/BootStrap.groovy
import demo.*

class BootStrap {

    def init = { servletContext ->

        println 'Before saving instance'
        def p = new Person(name: 'Peter')
            .addToComments(text: 'Comment One')
            .addToComments(text: 'Comment Two')
            .addToComments(text: 'Comment Three')
            .save(flush: true)

        println 'Before retrieving instance'

        def p2 = Person.get(p.id)

        println 'Before updating instance'
        p2.name = 'Peter Chou'
        p2.save()
    }
    def destroy = {
    }
}
Person.groovy

// grails-app/domain/demo/Comment.groovy
package demo

class Comment {
    String text
}
// grails-app/domain/demo/Person.groovy
package demo

class Person {
    String name
    static hasMany = [comments: Comment]
}
// grails-app/conf/BootStrap.groovy
import demo.*

class BootStrap {

    def init = { servletContext ->

        println 'Before saving instance'
        def p = new Person(name: 'Peter')
            .addToComments(text: 'Comment One')
            .addToComments(text: 'Comment Two')
            .addToComments(text: 'Comment Three')
            .save(flush: true)

        println 'Before retrieving instance'

        def p2 = Person.get(p.id)

        println 'Before updating instance'
        p2.name = 'Peter Chou'
        p2.save()
    }
    def destroy = {
    }
}
BootStrap.groovy

// grails-app/domain/demo/Comment.groovy
package demo

class Comment {
    String text
}
// grails-app/domain/demo/Person.groovy
package demo

class Person {
    String name
    static hasMany = [comments: Comment]
}
// grails-app/conf/BootStrap.groovy
import demo.*

class BootStrap {

    def init = { servletContext ->

        println 'Before saving instance'
        def p = new Person(name: 'Peter')
            .addToComments(text: 'Comment One')
            .addToComments(text: 'Comment Two')
            .addToComments(text: 'Comment Three')
            .save(flush: true)

        println 'Before retrieving instance'

        def p2 = Person.get(p.id)

        println 'Before updating instance'
        p2.name = 'Peter Chou'
        p2.save()
    }
    def destroy = {
    }
}
运行时,将创建以下输出:

Before saving instance
Hibernate: insert into person (id, version, name) values (null, ?, ?)
Hibernate: insert into comment (id, version, text) values (null, ?, ?)
Hibernate: insert into comment (id, version, text) values (null, ?, ?)
Hibernate: insert into comment (id, version, text) values (null, ?, ?)
Hibernate: insert into person_comment (person_comments_id, comment_id) values (?, ?)
Hibernate: insert into person_comment (person_comments_id, comment_id) values (?, ?)
Hibernate: insert into person_comment (person_comments_id, comment_id) values (?, ?)
Before retrieving instance
Before updating instance
Hibernate: update person set version=?, name=? where id=? and version=?
编辑:

我添加了一个控制器,其外观如下:

// grails-app/controllers/demo/DemoController.groovy
package demo

class DemoController {

    def index() {
        def p = Person.get(1)
        def numberOfComments = p?.comments?.size()
        p.name = "Name With Time: ${new Date()}"
        p.save(flush: true)

        render "Person has ${numberOfComments} comments."
    }
}
调用时,它向数据库发送一个查询以检索
Person
实例,另一个查询以检索
Comment
实例,最后向
Person
表发送更新

Hibernate: select person0_.id as id1_1_0_, person0_.version as version2_1_0_, person0_.name as name3_1_0_ from person person0_ where person0_.id=?
Hibernate: select comments0_.person_comments_id as person_c1_1_0_, comments0_.comment_id as comment_2_2_0_, comment1_.id as id1_0_1_, comment1_.version as version2_0_1_, comment1_.text as text3_0_1_ from person_comment comments0_ inner join comment comment1_ on comments0_.comment_id=comment1_.id where comments0_.person_comments_id=?
Hibernate: update person set version=?, name=? where id=? and version=?

正如你从伯特·贝克维思的博客文章中所读到的

在添加新注释时,让hasMany from Person进行注释至少可以获取所有注释

那么,这样构造代码可能会有所帮助

class Person {
    String name 

    static transients = ['comments']

    Collection<Comment> getComments() {
        Comment.findAllByPerson(this)
    }
}
在创建新注释时,而不是

person.addToComments(...)
干脆

new Comment(person: person, ...).save()

“Grails试图一个接一个地获取对象的所有关联”-“一个接一个”是否意味着如果您有20个关联,20个不同的
select
语句将被发送到数据库?是的,这就是我在日志中看到的。我不明白。模型或数据处理方式中可能存在相关但问题中未提及的内容。向数据库发送单独的
select
语句以检索每个单独的关联会很奇怪。如果你能在一个示例应用程序中重现这一点,请在链接到该应用程序时提交一个问题,我们可以对此进行调查。谢谢你的反馈,谢谢。我刚刚测试了一个新项目,也没有遇到这个问题。因此,现有项目中的某些配置一定导致了不必要的行为。如果/当我明白了这一点,我会发布。问题是有一个服务将域对象的子集保存到一个单独的mongo DB。我发现,如果删除mongodb grails插件依赖项,问题就会消失。因此,我相信我要做的是弄清楚如何配置插件,以忽略对mongo不持久的域对象的保存。