【问题标题】:How to configure Grails gorm save to not fetch all associations?如何将 Grails gorm save 配置为不获取所有关联?
【发布时间】:2017-01-14 05:51:32
【问题描述】:

我正在使用 Grails 2.5.4

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

class Person {
    String name 

    static hasMany = [comments: Comment] 
}

当我运行这样的代码时:

Person p = Person.get(1234)
p.save() 

查看休眠日志,我发现在实际更新 p 之前,Grails 尝试获取与 p 关联的每条评论,每条评论一个查询,并且保存的性能很差,即使我想要做的只是更新 p 的地址。

有什么方法可以配置域对象,以便 save() 忽略关联,因为很明显,我只会使用自己的保存服务(类似 commentService.addComment(params))保存评论,并且永远不会在我更新时人?

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

【问题讨论】:

  • “Grails 尝试一个一个地获取对象的所有关联” - “一个一个”是否意味着如果您有 20 个关联,则有 20 个不同的 select 语句被发送到数据库?
  • 是的,这就是我在日志中看到的。
  • 我不明白。模型中或处理数据的方式中可能存在相关但未在问题中提及的内容。
  • 向数据库发送单独的select 语句以检索每个单独的关联会很奇怪。如果您可以在示例应用程序中重现该问题,请在 github.com/grails/grails-core/issues 链接到该应用程序提交问题,我们可以对其进行调查。感谢您的反馈。

标签: hibernate grails grails-orm


【解决方案1】:

然后查看休眠日志,我看到在实际更新 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=?

【讨论】:

  • 谢谢。我刚刚用一个新项目进行了测试,也没有遇到这个问题。因此,现有项目中的某些配置一定会导致不需要的行为。如果/当我想通了,我会发布。
  • 问题原来是有一个服务将域对象的子集保存到单独的 mongo DB。我发现如果我删除 mongodb grails 插件依赖项,问题就会消失。所以,我相信我要做的就是弄清楚如何配置插件以忽略不保存到 mongo 的域对象上的保存。
【解决方案2】:

您可以从 Burt Beckwith 的博客文章中看到 https://mrpaulwoods.wordpress.com/2011/02/07/implementing-burt-beckwiths-gorm-performance-no-collections/

从 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()

【讨论】:

    猜你喜欢
    • 2022-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多