我正在开发 Grails 2.3.7 应用程序,但我在使用选择框更改域属性时遇到问题。每当我尝试更改属性并保存时,我都会得到HibernateException: identifier of an instance of Ethnicity was altered from X to Y
。我不想改变种族的身份,我只是想将ApplicationPerson
的种族从一个改为另一个。
有几点需要注意:
personInstance.ethnicity
之前将null
设置为personInstance.properties = params
将使保存工作,但我
不知道为什么,我不想为每个协会做这件事
我想改变。 以下是我的域类:
class ApplicationPerson implements Serializable {
Integer appId
Integer applicationSequenceNumber
String firstName
String lastName
Ethnicity ethnicity
static mapping = {
id composite: ['appId', 'applicationSequenceNumber'],
generator: 'assigned'
}
}
class Ethnicity {
String code
String description
static mapping = {
id name: 'code', generator: 'assigned'
}
}
我的_form.gsp
更新了Ethnicity
(我删除了所有其他保存得很好的属性):
<div class="fieldcontain ${hasErrors(bean: personInstance,
field: 'ethnicity', 'error')} ">
<label for="ethnicity">Ethnicity</label>
<g:select id="ethnicity"
name="ethnicity.code"
from="${Ethnicity.list()}"
optionKey="code"
value="${personInstance?.ethnicity?.code}" />
</div>
最后,我的控制器操作形式POST到:
def save() {
Application app = applicationService.getCurrentApplication()
// Find/Create and save Person
ApplicationPerson personInstance = app.person
if (!personInstance) {
personInstance =
new ApplicationPerson(appId: app.id,
applicationSequenceNumber: app.sequenceNumber)
}
personInstance.properties = params
if (!personInstance.validate()) {
respond personInstance.errors, view:'edit'
return
}
personInstance.save flush:true
redirect action: 'list'
}
答案 0 :(得分:2)
将select
元素中的名称从ethnicity.code
修改为personInstance.etnicity.code
,如下所示:
<g:select id="ethnicity"
name="personInstance.ethnicity.code"
from="${Ethnicity.list()}"
optionKey="code"
value="${personInstance?.ethnicity?.code}" />
所选选项的名称绑定到params
作为键,选定的值绑定为
value
反对密钥。使用ethnicity.code
会尝试修改现有ethnicity
的主键,而不是修改应用程序人员的种族。
<强>更新强>
名称的上述更改是可选的(可以在您不需要将params
指定为域类的属性的情况下使用)。以前的名称ethnicity.code
也应该有效,但在控制器操作中也需要进行更改以便设置种族:
//or use params.ethnicity.code
//if name is ethnicity.code
person.ethnicity = Ethnicity.load(params.personInstance.ethnicity.code)
//or use params if name is ethnicity.code
person.properties = params.personInstance
根据传入的Ethnicity
加载现有code
,然后在设置属性之前将其设置为person
。
问题在于code
是Ethnicity
的主键。如果Ethnicity
有一个单独的标识列(例如,默认的长id
),那么您的确切实现将在数据绑定的帮助下工作。但是,由于提到您正在使用旧数据库,我想您将无法修改表以添加id
的另一列。所以你最好的选择是load
(与从hibernate缓存中加载的行相比便宜)从传入的代码中获取种族,然后将其设置为person。
如果可能的话,您还可以看到尝试缓存种族域名,因为这将是主数据和缓存的良好候选者。