Grails Gorm:Object引用未保存的瞬态实例
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Grails Gorm:Object引用未保存的瞬态实例相关的知识,希望对你有一定的参考价值。
在Grails中保存Trip的实例时,我得到以下异常:
2011-01-26 22:37:42,801 [http-8090-5] ERROR errors.GrailsExceptionResolver - 对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例:Rower org.hibernate.TransientObjectException:object引用未保存的瞬态实例 - 在冲洗之前保存瞬态实例:Rower
这个概念很简单:对于乘船游览,你需要一些划船者,一个舵手(也是一个划船者)和一艘船:
旅行看起来像(缩短):
class Trip {
Boat boat;
Rower coxwain;
static belongsTo = [Rower,Boat]
static hasMany = [rowers:Rower]
}
和划船(缩短)
class Rower {
String firstname;
String name;
Rower reference;
static hasMany = [trips:Trip];
static mappedBy = [trips:"rowers"]
}
然后行程保存在控制器中,如:
def save = {
def trip = new Trip(params)
// adding Rowers to Trip
if (params.rower instanceof String) {
def r = Rower.get(params?.rower)
if (r != null) {
trip.addToRowers(r)
}
} else {
params?.rower?.each{
rowerid ->
def r = Rower.get(rowerid)
log.info("rowerid (asList): " + rowerid)
if (r != null) {
trip.addToRowers(r)
}
}
}
// saving the new Trip -> EXCEPTION IN NEXT LINE
if(!trip.hasErrors() && trip.save(flush:true)) {
// ...
}
// ...
}
我想我已经确定了域之间的关系是正确的。在将Rower添加到Trip中时,Rower不会更改。为什么Grails希望它保存?为什么它是一个瞬态实例?
不幸的是,这是GORM处理事物的方式的问题,或者更具体地说是它期望您处理瞬态的方式。如果您不首先将包含的类持久保存到数据库(在本例中为Rowers),则每次都会得到此异常。
使用GORM,您必须以自下而上的方式保存和附加,或者当grails用于刷新下一个实例的连接时,您将获得瞬态实例异常。该实例是“瞬态的”,因为它只是一个内存引用。要保留父级,GORM需要将父级链接到数据库中的子级。如果孩子没有被坚持,就无法做到这一点,这就是异常的来源。
希望有更好的消息。这不是很难,但它会因复杂的层次结构而变得烦人。
问题在某种程度上是不同的。它在这里:
def trip = new Trip(params)
它引用了一个未设置的coxwain(类Rower)(返回id = -1)。这构造了一个新的Rower而不是'null'值。这是'未保存的瞬态实例'。如果我先检查一个有效的实例,那么它的工作原理:-)
谢谢您的帮助!
对于处理具有相同名称的单个或多个参数的任何人来说,只需快速记录,使用params.list("parameterName")
帮助程序,您始终可以返回一个列表
...
// adding Rowers to Trip
if (params.rower instanceof String) {
def r = Rower.get(params?.rower)
if (r != null) {
trip.addToRowers(r)
}
} else {
params?.rower?.each{
rowerid ->
def r = Rower.get(rowerid)
log.info("rowerid (asList): " + rowerid)
if (r != null) {
trip.addToRowers(r)
}
}
}
...
可能会变得有点groovier
...
// adding Rowers to Trip
for(rower in params.list("rower") {
def r = Rower.get(rower)
if(r) trip.addToRowers(r)
}
...
你可以发现它隐藏在6.1.12 Simple Type Converters下
起初我认为它与级联保存和belongsTo有关,如The Grails Reference第5.2.1.3节和Gorm Gotchas part 2中所述。但是,由于Rowers已经在DB中,我认为它应该可行。域模型对我来说很复杂,您需要做的是简化它并使用Grails控制台运行一些测试(在项目目录中运行grails控制台)。首先在Trip和Rower之间创建一个基本的多对多,并让它执行所需的代码。然后逐位添加其他部分,如Rower对自身的引用。我不确定mappedBy部分是否必要。
我认为你必须在将火星车添加到旅行之前保存行程。在验证和/或保存之前检查行程是否有错也没有意义。
试试这个:
if(trip.validate() && trip.save(flush:true)) {
if (r != null) {
trip.addToRowers(r)
}
}
在许多用例中,您应该能够通过将cascade
设置应用于您的集合来解决此问题:
static mapping = {
rowers cascade: 'all-delete-orphan'
}
https://docs.grails.org/latest/ref/Database%20Mapping/cascade.html
假设,你正在使用Trip与Rower有很多关系
class Trip {
static hasMany = [rowers:Rower]
...
}
class Rower{
static belongsTo =[trips:Trip]
...
}
实际上,它正在寻找新的会议。所以我们需要停止/回滚当前事务然后这个错误不会引发,为此尝试这个,
def row = new Row()
row.save()
注意:此保存不会影响您的数据库。它只是用于回滚事务。
以上是关于Grails Gorm:Object引用未保存的瞬态实例的主要内容,如果未能解决你的问题,请参考以下文章
HIbernate - 对象引用未保存的瞬态实例 - 在刷新之前保存瞬态实例
数据未保存:对象引用了未保存的瞬态实例 - 在刷新之前保存瞬态实例 [重复]