如果发生错误或域类无效,我要做的主要工作是返回到编辑页面。我有一个User对象,它包含一个Person对象作为属性。
我的控制器看起来是这样的:
Object update(){
User.withTransaction{status ->
try {
personDaoService?.bindObject(person, params)
person.validate()
} catch(Exception e){
log.error(e.printStackTrace())
status.setRollbackOnly()
}
if(person.hasErrors()){
status.setRollbackOnly()
}
if(status.isRollbackOnly()){
person.discard()
person.refresh()
return render(view: 'edit', model:[user:user, person:person], params: params)
}
try {
userDaoService?.bindObject(person, params)
user.validate()
} catch(Exception e){
log.error(e.printStackTrace())
status.setRollbackOnly()
}
if(status.isRollbackOnly()){
user.discard()
user.refresh()
return render(view: 'edit, model:[user:user, person:person], params: params)
}
}
}当返回到编辑页面时,我总是得到一个异常,它告诉我没有打开会话来加载person对象。
为了快速解决这个问题,我在用户对象的映射中添加了lazy:false,但结果不幸的是整个项目运行非常缓慢,所以我不得不删除lazy:false映射选项。
现在我想找个办法让它再起作用。
为什么hibernate在回滚时关闭会话?
我怎样才能重开会议?
编辑:
在设置回滚之前,我尝试呈现视图:
if(person.hasErrors()){
person.errors.allErrors.each{user.errors.rejectValue("person", "", "${validationTagLib.message(error: it)}")}
render(view: 'edit', model: [user: user], params: params)
status.setRollbackOnly()
return
}这导致了这个异常:org.hibernate.LazyInitializationException: could not initialize proxy - no Session
发布于 2017-11-06 10:55:12
我在DomainClasses中创建了一个方法来加载所需的所有对象,并在返回到编辑页面时调用该方法:
Object update(){
User.withTransaction{status ->
try {
personDaoService?.bindObject(person, params)
person.validate()
} catch(Exception e){
log.error(e.printStackTrace())
status.setRollbackOnly()
}
if(person.hasErrors()){
status.setRollbackOnly()
}
if(status.isRollbackOnly()){
person.discard()
person.refresh()
loadObject(person)
return render(view: 'edit', model:[user:user, person:person], params: params)
}
try {
userDaoService?.bindObject(person, params)
user.validate()
} catch(Exception e){
log.error(e.printStackTrace())
status.setRollbackOnly()
}
if(status.isRollbackOnly()){
user.discard()
user.refresh()
loadObject(user)
return render(view: 'edit', model:[user:user, person:person], params: params)
}
}
}加载类型为domainClass的所有属性的方法如下所示:
void loadObject(Object object, List<Object> loadedObjects = []){
loadedObjects.add(object)
for(MapEntry propertyEntryMap in object.properties){
Object property = propertyEntryMap?.value
if(grailsApplication.isDomainClass(property.getClass())){
if(!loadedObjects.contains(property))
loadObject(property, loadedObject)
}
}
if(object.hasProperty("hasMany")){
for(def manyProperty in object.hasMany){
for(Object property in object."${manyProperty.key}"){
if(grailsApplication.isDomainClass(property.getClass())){
if(!loadedObjects.contains(property))
loadObject(property, loadedObject)
}
}
}
}
}唯一可以解决的问题是,hasMany关系可能太大了,这会减慢它的速度。
为了解决这个问题,我向DomainClass添加了一个属性,该属性包含应该加载的hasMany关系:
static lazyProperties = ['addresses']此属性影响将跨越该列表中属性的loadObject方法:
void loadObject(Object object, List<Object> loadedObjects = []){
loadedObjects.add(object)
for(MapEntry propertyEntryMap in object.properties){
Object property = propertyEntryMap?.value
if(object.hasProperty('lazyProperties')){ // check if object contains the property 'lazyProperties'
if(object?.lazyProperties?.contains(propertyEntryMap.key))
continue
}
if(grailsApplication.isDomainClass(property.getClass())){
if(!loadedObjects.contains(property))
loadObject(property, loadedObject)
}
}
if(object.hasProperty("hasMany")){
for(def manyProperty in object.hasMany){
if(object.hasProperty('lazyProperties')){ // check if object contains the property 'lazyProperties'
if(object?.lazyProperties?.contains(manyProperty.key))
continue
}
for(Object property in object."${manyProperty.key}"){
if(grailsApplication.isDomainClass(property.getClass())){
if(!loadedObjects.contains(property))
loadObject(property, loadedObject)
}
}
}
}
}发布于 2017-11-02 23:32:06
试图对上面的评论进行扩展。
这个错误意味着发生了严重的错误,因此hibernate必须关闭会话。
考虑到这个控制器:
def doSomething() {
SomeBean bean = new SomeBean(params.long('id'))
bean.updateUser=userService.currentUser
try {
serice.foSomething(bean)
} catch (ValidationException ve) {
flash.message=message(error:ve.errors.getGlobalError())?:ve.errors
} catch (DataIntegrityViolationException e) {
} catch (HibernateObjectRetrievalFailureException e) {
} catch (Throwable t) {
flash.message= t.toString()
}
redirect(controller:'someController', action:'list')
}它有这么多尝试捕获的原因是因为我发现,例如,对于我正在获取HibernateObjectRetrievalFailureException的一段代码,但是实际的工作已经完成了--这使得您所勾勒出的这种secnario发生了--或者可能发生。
我的意思是,尝试在服务方法周围使用try捕获,并计算出首先发生了什么。
最重要的是,前3次尝试捕捉实际上告诉控制器继续进行--忽略这些问题(我认为在本例中它们都是这样),但是如果没有重定向,您可以在可抛出的段中添加一些子句或重定向,所以您可以选择其他地方,或者忽略它。
要完成以上所有内容,这可能对你有帮助将修复您的问题。
import grails.validation.ValidationException
class AuthorService {
void updateAge(id, int age) {
def author = Author.get(id)
author.age = age
if (!author.validate()) {
throw new ValidationException("Author is not valid", author.errors)
}
}
}基本上,当您最终捕获问题并找出导致问题的原因时,您可以在它发生之前捕获它,并返回您自己的自定义验证异常。
这将被你的标准故障所发现,其他的一切都会顺利地完成。
您的图层可以验证并确保一切正常--您显示的当前验证层--而问题其实并不在这里--当您要求Hibernate并去做一些无效的事情时--删除不能移除的东西--做一些它不能删除的事情--然后破坏它,并引起您当前的头痛--因此,在发生之前捕获它们,然后做上面的操作将是如何解决这些问题的。
https://stackoverflow.com/questions/47072654
复制相似问题