我正在使用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对象上的一些字段值,同时完全忽略任何映射的关联。因此没有理由获取关联。
答案 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)
从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()