How can I use embedded GORM classes in Grails?

元气小坏坏 提交于 2019-12-22 08:57:50

问题


Following the GORM docs I tried to use the following domain class with Grails 2.2.1:

package grailscompositiontest

class ScafPerson {
    String name
    ScafAddress homeAddress
    ScafAddress workAddress

    static constraints = {
        name(nullable: false, blank: false)
    }

    static embedded = ['homeAddress', 'workAddress']
}

class ScafAddress {
    String number
    String code
}

The controller just uses scaffolding:

package grailscompositiontest

class ScafPersonController {
    static scaffold = true
}

Unfortunately this does not work, it triggers a server error as soon as I browse to the "create" view:

URI:     /GrailsCompositionTest/scafPerson/create
Class:   java.lang.NullPointerException
Message: Cannot get property 'id' on null object

Any idea what I am doing wrong?


回答1:


I found that the grails documentation says to put embedded class definitions either the same source file as the domain class or put it into src/groovy. I put Address.groovy in src/groovy and generated the UI for my Family class, which has an embedded object. The generated create page now displays correctly with the address fields are included in the Family page. However, I still had to modify the name and the value fields of each form field in the generated _form.gsp.

For example, the following generated code...

<g:textField name="line1" required="" value="${addressInstance?.line1}"/>

was changed to...

<g:textField name="address.line1" required="" value="${familyRegistrationInstance.address?.line1}"/>

Where the primary domain object is a FamilyRegistration domain class (referred to in the generated _form.jsp as familyRegistrationInstance), which has an embedded Address object. I am using grails 2.3.11.

The save operation now works with the fields of the embedded object populated correctly. In my case, this means that FamilyRegistration.address is populated correctly.

Here's the related info from the Grails Reference document...

"The embedded component class is typically declared in the same source file as the owning class or in its own file under src/groovy. You can put the component class under grails-app/domain, but if you do so Grails will automatically create a dedicated table for it. Putting the class under src/groovy is usually the best option because you can then share the component across multiple domain classes."

http://grails.org/doc/2.2.4/ref/Domain%20Classes/embedded.html




回答2:


I ran into this same problem the other day. I believe there may be a bug in the templates used by the scaffolding functionality. You can either update the template or if you don't want to muck with the templates, run generate-all as Benoit mentioned then fix the generated view.

To update template:

  1. grails> install-templates
  2. open src/templates/scaffolding/renderEditor.template
  3. find the following line:
    sb << ' value="${' << domainInstance << '.' << property.name << '}"'

and change to

    sb << ' value="${' << domainInstance << '?.' << property.name << '}"'

To fix the generated view:

  1. grails> generate-all grailscompositiontest.ScafPerson
  2. open views/scafPerson/_form.gsp
  3. look for
    <g:field name="id" type="number" value="${scafAddressInstance.id}" required=""/>
    <g:field name="version" type="number" value="${scafAddressInstance.id}" required=""/>

and change to

    <g:field name="id" type="number" value="${scafAddressInstance?.id}" required=""/>
    <g:field name="version" type="number" value="${scafAddressInstance?.id}" required=""/>

Note you'll do it twice since you have homeAddress/workAddress



来源:https://stackoverflow.com/questions/15902093/how-can-i-use-embedded-gorm-classes-in-grails

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!