Grails独特的复合关键问题
给定一个GORM类:Grails独特的复合关键问题,grails,gorm,Grails,Gorm,给定一个GORM类: class PriceSheet { Client client Population population Product product RevenueModelType modelType BigDecimal price static constraints = { client(unique: ['population', 'product', 'modelType']) } }
class PriceSheet {
Client client
Population population
Product product
RevenueModelType modelType
BigDecimal price
static constraints = {
client(unique: ['population', 'product', 'modelType'])
}
}
我希望只有在客户、总体、产品和型号都是唯一的情况下,才能保存/更新价格表。(对于客户、总体、产品和型号组合,应该只有一个价格表项目)
密钥正在mySQL中创建
我的问题是grails验证通过了,但保存失败
priceSheetInstance.validate()
if (priceSheetInstance.hasErrors()) {
respond priceSheetInstance.errors, view:'create'
return
}
priceSheetInstance.save flush:true
有什么想法或建议吗?我在验证后将调试器放在断点上,并看到错误为空
Grails 2.3.10首先,您需要告诉GORM哪些属性构成了复合主键,然后您的域类需要实现可序列化。最终的结果是这样的:
import org.apache.commons.lang.builder.HashCodeBuilder
class PriceSheet implements Serializable {
Client client
Population population
Product product
RevenueModelType modelType
BigDecimal price
static constraints = {
}
static mapping = {
id composite: ['client', 'population', 'product', 'modelType']
}
boolean equals(other) {
if(!(other instanceof PriceSheet)) return false
other.client == client && other.population == population && other.product == product && other.modelType == modelType
}
int hashCode() {
def builder = new HashCodeBuilder()
builder.with {
append client
append population
append product
append modelType
}
builder.toHashCode()
}
}
您可以阅读有关GORM复合键的更多信息。首先,您需要告诉GORM哪些属性构成了复合主键,然后您的域类需要实现可序列化。最终的结果是这样的:
import org.apache.commons.lang.builder.HashCodeBuilder
class PriceSheet implements Serializable {
Client client
Population population
Product product
RevenueModelType modelType
BigDecimal price
static constraints = {
}
static mapping = {
id composite: ['client', 'population', 'product', 'modelType']
}
boolean equals(other) {
if(!(other instanceof PriceSheet)) return false
other.client == client && other.population == population && other.product == product && other.modelType == modelType
}
int hashCode() {
def builder = new HashCodeBuilder()
builder.with {
append client
append population
append product
append modelType
}
builder.toHashCode()
}
}
您可以阅读有关GORM复合键的更多信息。最终解决方案是在控制器中使用NewSession进行保存:
PriceSheet.withNewSession {
priceSheetInstance.validate()
// needed to call save in order to check the unique compound key
// validate alone wasn't working
// also needed to wrap withNewSession above
// PriceSheet GORM object implements Serializable as well
// spent way more time than expected on this.... wrestled with Grails
if (priceSheetInstance.hasErrors() || (priceSheetInstance.save(failOnError: true) && priceSheetInstance.hasErrors())) {
respond priceSheetInstance.errors, view:'create'
return
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'priceSheet.label', default: 'Price Sheet'), priceSheetInstance?.id])
redirect (action: 'index')
}
'*' { respond priceSheetInstance, [status: CREATED] }
}
}
我不必用NewSession包装更新。。。事实上,使用NewSession包装更新会导致过时的对象异常最终解决方案是在controller中使用NewSession包装保存:
PriceSheet.withNewSession {
priceSheetInstance.validate()
// needed to call save in order to check the unique compound key
// validate alone wasn't working
// also needed to wrap withNewSession above
// PriceSheet GORM object implements Serializable as well
// spent way more time than expected on this.... wrestled with Grails
if (priceSheetInstance.hasErrors() || (priceSheetInstance.save(failOnError: true) && priceSheetInstance.hasErrors())) {
respond priceSheetInstance.errors, view:'create'
return
}
request.withFormat {
form multipartForm {
flash.message = message(code: 'default.created.message', args: [message(code: 'priceSheet.label', default: 'Price Sheet'), priceSheetInstance?.id])
redirect (action: 'index')
}
'*' { respond priceSheetInstance, [status: CREATED] }
}
}
我不必用NewSession包装更新。。。事实上,使用NewSession包装更新会导致StaleObjectExceptions感谢您的选择,但我不希望主键是复合键。根据文档,我应该能够在尝试使用unique Validator时这样做是的,但您必须记住这一点(直接从文档中):唯一性验证可能会通过,但随后的保存会失败(尽管在实践中不太可能)。如果在Grails检查和实例的实际保存之间发生另一次保存或更新来更新数据库,则调用将失败。防止这种情况的唯一方法是在可序列化隔离级别使用事务,但这对性能非常不利。您最好先调用save()然后检查错误。谢谢您的选择,但我不希望主键是复合键。根据文档,我应该能够在尝试使用unique Validator时这样做是的,但您必须记住这一点(直接从文档中):唯一性验证可能会通过,但随后的保存会失败(尽管在实践中不太可能)。如果在Grails检查和实例的实际保存之间发生另一次保存或更新来更新数据库,则调用将失败。防止这种情况的唯一方法是在可序列化隔离级别使用事务,但这对性能非常不利。最好先调用save(),然后检查错误。