Hibernate 如何配置Grails gorm save以不获取所有关联?
我正在使用Grails2.5.4Hibernate 如何配置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相关的每个注释,每个注释一个查询
我注意到,如果调用域对象的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不持久的域对象的保存。