简体   繁体   English

无法在 Grails 中更改域类属性值

[英]Cannot change domain class property value in Grails

I am developing a Grails 2.3.7 application and I'm having trouble changing a domain property with a select box.我正在开发Grails 2.3.7应用程序,但在使用选择框更改域属性时遇到问题。 Every time I try to change the property and save, I get a HibernateException: identifier of an instance of Ethnicity was altered from X to Y .每次我尝试更改属性并保存时,我都会收到一个HibernateException: identifier of an instance of Ethnicity was altered from X to Y I don't want to change the ID of the ethnicity, I simply want to change the ApplicationPerson s ethnicity from one to another.我不想更改种族的 ID,我只想将ApplicationPerson的种族从一种更改为另一种。

A few things to note:需要注意的几点:

  1. I am using the same controller action to create AND update the person.我正在使用相同的控制器操作来创建和更新此人。
  2. Setting personInstance.ethnicity to null right before personInstance.properties = params will make the save work, but I don't know why, and I don't want to do this for every association that I want to change.personInstance.properties = params之前将personInstance.ethnicity设置为null将使保存工作,但我不知道为什么,我不想为我想要更改的每个关联都这样做。
  3. I realize the domain model seems odd.我意识到域模型看起来很奇怪。 It is a legacy DB that I cannot change.这是一个我无法更改的旧数据库。

Here are my domain classes:这是我的域类:

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'
    }
}

Here is my _form.gsp to update the Ethnicity (I removed all the other properties that are saving just fine):这是我的_form.gsp来更新Ethnicity (我删除了所有其他保存_form.gsp属性):

<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>

And lastly, my controller action that the form POSTs to:最后,表单发布到我的控制器操作:

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'
}

Modify the name in the select element from ethnicity.code to personInstance.etnicity.code as shown below:select元素中的name从ethnicity.code修改为personInstance.etnicity.code ,如下图:

<g:select id="ethnicity" 
          name="personInstance.ethnicity.code" 
          from="${Ethnicity.list()}" 
          optionKey="code" 
          value="${personInstance?.ethnicity?.code}" />

The name of selected option gets bound to params as key and the selected value as the value against the key.所选选项的名称绑定到params作为键,所选值作为键的value Using ethnicity.code would try to modify the primary key of an existing ethnicity instead of modifying the ethnicity of an application person.使用ethnicity.code将尝试修改现有ethnicity的主键,而不是修改应用程序人员的种族。

UPDATE更新
Above change in name is optional (can be used in case you don't need params to be assigned as properties of domain class).以上名称更改是可选的(可以在不需要将params分配为域类属性的情况下使用)。 Previous name ethnicity.code should work as well but below changes are also required in the controller action in order to set ethnicity:以前的名称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

Load an existing Ethnicity based on the passed in code and then set it in person before setting properties.根据传入的code加载现有的Ethnicity ,然后在设置属性之前person设置它。

The issue lies with code being the primary key of Ethnicity .问题在于codeEthnicity的主键。 If Ethnicity had a separate identity column (for example, the default Long id ) then your exact implementation in question would work with the help of data binding.如果Ethnicity有一个单独的标识列(例如,默认的 Long id ),那么您的确切实现将在数据绑定的帮助下工作。 But since it is mentioned that you are working with legacy database, I suppose you won't be able to modify the tables to add another column for id .但是由于提到您正在使用旧数据库,我想您将无法修改表来为id添加另一列。 So your best bet will be to load (cheap compared to get, as row is loaded from hibernate cache) ethnicity from the passed in code and then set it to person.因此,您最好的选择是从传入的代码中load (与 get 相比便宜,因为行是从休眠缓存加载的)种族,然后将其设置为 person。

You can also see try caching the Ethnicity domain if possible because that will be master data and a good candidate for caching.如果可能,您还可以尝试缓存 Ethnicity 域,因为这将是主数据和缓存的良好候选者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM