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

时间:2016-09-06 17:24:11

标签: hibernate grails gorm

我正在使用Grails 2.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()忽略关联,因为很明显我只会用自己的保存服务保存Comment(类似于commentService.addComment(params)),而且从来没有我正在更新人?

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

2 个答案:

答案 0 :(得分:1)

  

看看hibernate日志,我在实际更新p之前看到了   Grails尝试获取与p相关的每个注释,每个查询一个查询   评论,保存有可怕的表现

我无法重现这一点。请参阅https://github.com/jeffbrown/peterchou上的项目。

<强> Comment.groovy

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

class Comment {
    String text
}

<强> Person.groovy

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

class Person {
    String name
    static hasMany = [comments: Comment]
}

<强> BootStrap.groovy中

// 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=?

修改

我在https://github.com/jeffbrown/peterchou/commit/8c1f6a289cc0a6cff54e5b9fb9d1fed3e19b9760添加了一个控制器,如下所示:

// 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."
    }
}

调用时,会向数据库发送1个查询以检索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=?

答案 1 :(得分:0)

您可以在https://mrpaulwoods.wordpress.com/2011/02/07/implementing-burt-beckwiths-gorm-performance-no-collections/

上阅读Burt Beckwith的博客文章

从Person到Comment的hasMany至少会在添加新的注释时获取所有注释。

所以,或许像这样构建你的代码会有所帮助吗?

class Person {
    String name 

    static transients = ['comments']

    Collection<Comment> getComments() {
        Comment.findAllByPerson(this)
    }
}

评论应该仍然具有对人员的属性:

class Comment {
    static belongsTo = [person: Person]
}

并在创建新评论时,而不是

person.addToComments(...)

简单地做

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