最近我试图修复Grails" not-null属性引用空值或瞬态值"没有太多运气的例外。
我有4个域类:
条形码:
class Barcode {
BarcodeConfiguration barcodeConfiguration //holds where/how many barcodes should print, and which sequence iterates
AppUser creationUser
Date dateCreated = new Date()//bug in gorm means I have to do this manually
//scannable barcode consists of prefix + sequenceId. These typically form the text as well, but not always
String prefix //typically 3 letters description (eg: HIP, PAT, VAC). Denormalized from barcodeConfiguration to improve queries and ensure truth if barcodeConfig updated later.
Long sequenceId //id printed for the sequence in barcodeConfiguration
String text //text that describes the barcode - typically prefix + sequenceId, but different for controls where CTR1_[0-9]+ is used instead of CTR1
BatchRes batch
Boolean active = true
static constraints = {
batch(nullable: true)
...
}
}
BatchRes:
class BatchRes {
def springSecurityService
def sessionFactory
Pipeline pipeline
AppUser operator
List<Barcode> barcodes
static hasMany = [
selectedControls: ControlLot,
barcodes: Barcode
]
}
批号:
class Lot implements Comparable<Lot> {
static auditable = true
// note: belongsTo seems to be needed for cascading validation (without custom validator)
static belongsTo = [sample:Sample]
static hasMany = [containers:Container]
Integer lotNumber
static constraints = {
// enforce uniqueness of lotNumber among lots for a given Sample
lotNumber(unique:'sample', validator:{it > 0})
}
}
ControlLot:
class ControlLot extends Lot {
public static final String BARCODE_PREFIX = "CTR"
boolean passQC = false
boolean active = false
Date passQCDate
Container sourceContainer
}
ControlLotService:
class ControlLotService {
ControlLot createControlLot(ControlLotCommand command) {
ControlSample sample = ControlSample.get(command.controlId)
// container first
ControlContainer sourceContainer = new ControlContainer()
BarcodeConfiguration barcodeConfiguration = BarcodeConfiguration.findByName(ControlLot.BARCODE_PREFIX)
sourceContainer.barcodeObject = barcodeService.createBarcode(barcodeConfiguration, null, null,
sample.name)
sourceContainer.save(flush: true)
// lot second
ControlLot controlLot = new ControlLot()
controlLot.sample = sample
controlLot.lotNumber = sourceContainer.barcodeObject.sequenceId
controlLot.sourceContainer = sourceContainer
controlLot.save(flush: true)
controlLot.sourceContainer.lot = controlLot
controlLot.save()
return controlLot
}
}
BarcodeService:
class BarcodeService {
Barcode createBarcode(BarcodeConfiguration barcodeConfig,
BatchRes batch = null,
Long sequenceId = null,
String text = null) {
if (!sequenceId){
sequenceId = getSequenceNumber(batch, barcodeConfig)
}
// use blank constructor to fix HERO-302
Barcode barcode = new Barcode()
if(batch) {
barcode.batch = batch
}
barcode.barcodeConfiguration = barcodeConfig
barcode.prefix = barcodeConfig.prefix
barcode.sequenceId = sequenceId
barcode.text = text?:barcodeConfig.prefix + sequenceId
barcode.creationUser = springSecurityService.currentUser as AppUser
if (batch){
log.info("Adding ${barcode} to ${batch}")
batch.addToBarcodes(barcode)
batch.save()//Following http://grails.org/doc/2.3.x/guide/GORM.html#sets,ListsAndMaps example Saves cascade down from one to many
}
else{
barcode.save(flush: true)//need to explicitly save barcode if not attached to batch
}
barcodeConfig.isEditable = false
barcode
}
}
我收到以下错误消息:
2015-01-14 11:05:01,386 [http-bio-9090-exec-46] ERROR org.codehaus.groovy.grails.orm.hibernate.events.PatchedDefaultFlushEventListener - Could not synchronize databa
se state with session
org.hibernate.PropertyValueException: not-null property references a null or transient value: com.gsg.enterprise.domain.lims.Barcode._BatchRes_barcodesBackref
at com.gsg.enterprise.service.BarcodeService.createBarcode(BarcodeService.groovy:78)
at GrailsMelodyGrailsPlugin$_closure4_closure16_closure17.doCall(GrailsMelodyGrailsPlugin.groovy:184)
at com.gsg.enterprise.service.ControlService.createControlLot(ControlService.groovy:107)
at GrailsMelodyGrailsPlugin$_closure4_closure16_closure17.doCall(GrailsMelodyGrailsPlugin.groovy:184)
at com.gsg.enterprise.domain.lims.ControlLotController$_saveNew_closure4.doCall(ControlLotController.groovy:176)
at com.gsg.enterprise.domain.lims.ControlLotController.saveNew(ControlLotController.groovy:171)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:200)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:151)
at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:277)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:208)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:181)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
2015-01-14 11:05:01,447 [http-bio-9090-exec-46] ERROR grails.app.controllers.com.gsg.enterprise.domain.lims.ControlLotController - not-null property references a nul
l or transient value: com.gsg.enterprise.domain.lims.Barcode._BatchRes_barcodesBackref; nested exception is org.hibernate.PropertyValueException: not-null property re
ferences a null or transient value: com.gsg.enterprise.domain.lims.Barcode._BatchRes_barcodesBackref
org.springframework.dao.DataIntegrityViolationException: not-null property references a null or transient value: com.gsg.enterprise.domain.lims.Barcode._BatchRes_barc
odesBackref; nested exception is org.hibernate.PropertyValueException: not-null property references a null or transient value: com.gsg.enterprise.domain.lims.Barcode.
_BatchRes_barcodesBackref
at com.gsg.enterprise.service.BarcodeService.createBarcode(BarcodeService.groovy:78)
at GrailsMelodyGrailsPlugin$_closure4_closure16_closure17.doCall(GrailsMelodyGrailsPlugin.groovy:184)
at com.gsg.enterprise.service.ControlService.createControlLot(ControlService.groovy:107)
at GrailsMelodyGrailsPlugin$_closure4_closure16_closure17.doCall(GrailsMelodyGrailsPlugin.groovy:184)
at com.gsg.enterprise.domain.lims.ControlLotController$_saveNew_closure4.doCall(ControlLotController.groovy:176)
at com.gsg.enterprise.domain.lims.ControlLotController.saveNew(ControlLotController.groovy:171)
at grails.plugin.cache.web.filter.PageFragmentCachingFilter.doFilter(PageFragmentCachingFilter.java:200)
at grails.plugin.cache.web.filter.AbstractFilter.doFilter(AbstractFilter.java:63)
at net.bull.javamelody.JspWrapper.invoke(JspWrapper.java:151)
at net.bull.javamelody.JdbcWrapper$DelegatingInvocationHandler.invoke(JdbcWrapper.java:277)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:208)
at net.bull.javamelody.MonitoringFilter.doFilter(MonitoringFilter.java:181)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
at java.lang.Thread.run(Thread.java:619)
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: com.gsg.enterprise.domain.lims.Barcode._BatchRes_barcodesBackref
我使用的Grails版本是2.2.1版本