【问题标题】:Cannot change domain class property value in Grails无法更改 Grails 中的域类属性值
【发布时间】:2014-04-13 17:00:25
【问题描述】:

我正在开发一个 Grails 2.3.7 应用程序,但在使用选择框更改域属性时遇到问题。每次我尝试更改属性并保存时,我都会得到一个HibernateException: identifier of an instance of Ethnicity was altered from X to Y。我不想更改种族的ID,我只是想将ApplicationPersons 的种族从一个更改为另一个。

需要注意的几点:

  1. 我正在使用相同的控制器操作来创建和更新人员。
  2. personInstance.properties = params 之前将personInstance.ethnicity 设置为null 将使保存工作,但我 不知道为什么,我不想为每个协会都这样做 我想改变。
  3. 我意识到域模型似乎很奇怪。这是一个我无法更改的遗留数据库。

这是我的域类:

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

【问题讨论】:

  • 复合键中的aidm 是什么?
  • 一个错字。感谢您指出这一点。
  • 您使用迁移脚本吗?备份后自动创建数据库怎么样...?
  • 不幸的是,事情没那么简单。这是一所大学的遗留数据库。我不能真正改变任何东西,只需要在它之上创建一个应用程序。

标签: grails grails-orm grails-2.0 grails-domain-class


【解决方案1】:

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

根据传入的code加载一个已有的Ethnicity,然后在设置属性前设置在person中。

问题在于codeEthnicity 的主键。如果 Ethnicity 有一个单独的标识列(例如,默认的 Long id),那么您的确切实现将在数据绑定的帮助下工作。但是由于提到您正在使用旧数据库,我想您将无法修改表来为id 添加另一列。所以你最好的选择是load(与get相比便宜,因为行是从休眠缓存中加载的)从传入的代码中选择种族,然后将其设置为人。

如果可能,您还可以尝试缓存 Ethnicity 域,因为这将是主数据并且是缓存的良好候选者。

【讨论】:

  • 我试过这个但没有任何运气。我没有我也试过name="applicationPerson.ethnicity.code" 没有运气。 :(
  • 不,当我做出改变时,它根本不会改变人的种族。有点像数据绑定不会发生。我也觉得奇怪的是,在personInstance.properties = params 之前执行personInstance.ethnicity = null 会使一切正常。我是否可能错误地映射了我的域类?在数据库中,Person 表有一个 ethnicity_code 字段映射到 Ethnicity...所以我很确定我正确映射了它
  • 查看我的更新,种族必须加载然后设置为person
  • 感谢您的更新。我会在早上试一试。我希望避免向控制器添加额外的依赖项并简单地使用person.properties = params,但看起来我不会那么简单。
  • 正如我所说,如果 Ethnicity 有一个单独的 id 列,那么一切都会按预期工作。 :)
猜你喜欢
  • 2012-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多