Results 1 to 7 of 7

Thread: Is possible to create a domain and its related domain objects in one line?

  1. #1
    Join Date
    Nov 2010
    Posts
    13

    Exclamation Is possible to create a domain and its related domain objects in one line?

    Hello,

    I'm part of a team of developers and we're working in our second grails project. We're still learning some great features of grails and one question has come to our mind.

    We have some domain classes with relationships to others. My question is.. is there a way to hydrate (fill in the attributes of the domain with, for example, the params map) a domain object and its relationships?
    For example, if I have these two domain classes:

    User{
    String name
    String NIF
    static belongsTo = [profile:Profile]
    }

    Profile {
    String profileName
    }

    and I have a form like this one:

    <g:form name="userForm" action="save">
    <g:textField name="name" value="${userInstance?.name}"/>
    <g:textField name="NIF" value="${userInstance?.NIF}"/>
    <g:textField name="profile.profileName" value="${userInstance?.profile?.profileName}"/>
    <g:submitButton name="create" value="Create"/>
    </g:form>

    could we in the controller just write this to save the user and the profile?

    def save = {
    def userInstance = new User(params)
    user.save()
    ...
    }

    Many thanks.

  2. #2
    Join Date
    Jun 2010
    Location
    London
    Posts
    304

    Default

    Yes, that should work. Is it not?

  3. #3
    Join Date
    Nov 2010
    Posts
    13

    Default Is possible to create a domain and its related domain objects in one line?

    I have tried with the following code and it doesn't work.

    Gives this error:
    org.hibernate.PropertyValueException: not-null property references a null or transient value: pruebadomain.User.profile
    at $Proxy11.saveOrUpdate(Unknown Source)
    at pruebadomain.UserController$_closure4.doCall(prueb adomain.UserController:27)
    at pruebadomain.UserController$_closure4.doCall(prueb adomain.UserController)
    at java.lang.Thread.run(Thread.java:619)


    def create = {
    def userInstance = new User()
    userInstance.properties = params
    def profileInstance = new Profile()
    userInstance.profile = profileInstance
    return [userInstance: userInstance]
    }

    def save = {
    def userInstance = new User(params)
    if (userInstance.save(flush: true)) {
    flash.message = "${message(code: 'default.created.message', args: [message(code: 'user.label', default: 'User'), userInstance.id])}"
    redirect(action: "show", id: userInstance.id)
    }
    else {
    render(view: "create", model: [userInstance: userInstance])
    }
    }


    and in the view

    <g:form action="save" >
    <div class="dialog">
    <table>
    <tbody>

    <tr class="prop">
    <td valign="top" class="name">
    <label for="NIF"><g:message code="user.NIF.label" default="NIF" /></label>
    </td>
    <td valign="top" class="value ${hasErrors(bean: userInstance, field: 'NIF', 'errors')}">
    <g:textField name="NIF" value="${userInstance?.NIF}" />
    </td>
    </tr>

    <tr class="prop">
    <td valign="top" class="name">
    <label for="name"><g:message code="user.name.label" default="Name" /></label>
    </td>
    <td valign="top" class="value ${hasErrors(bean: userInstance, field: 'name', 'errors')}">
    <g:textField name="name" value="${userInstance?.name}" />
    </td>
    </tr>

    <tr class="prop">
    <td valign="top" class="name">
    <label for="profile"><g:message code="user.profile.label" default="Profile" /></label>
    </td>
    <td valign="top" class="value ${hasErrors(bean: userInstance, field: 'profile', 'errors')}">
    <g:textField name="profile.profileName" value="${userInstance?.profile?.profileName}"/>
    </td>
    </tr>

    </tbody>
    </table>
    </div>
    <div class="buttons">
    <span class="button"><g:submitButton name="create" class="save" value="${message(code: 'default.button.create.label', default: 'Create')}" /></span>
    </div>
    </g:form>

  4. #4
    Join Date
    Jun 2010
    Location
    London
    Posts
    304

    Default

    OK, I see what the problem is. In order to do this, you need the save to cascade from the user to the profile. You enable cascading saves via the belongsTo property, which you have but on the wrong class. If you're saving User, then Profile should have a belongsTo to User.

    With the current relationships, you need to bind data to Profile and save that.

    Hope that helps.

  5. #5
    Join Date
    Nov 2010
    Posts
    13

    Default

    You're right, thanks.

    I have changed my domain classes to the following:

    class Profile {
    String profileName

    static belongsTo = [user:User]
    static constraints = {
    }
    }

    class User {
    String name
    String NIF
    Profile profile

    static constraints = {
    }
    }

    This works, but I had to add the profile field in the user domain to be able to create the user and the profile as I said in my last post. Is this ok?

  6. #6
    Join Date
    Jun 2010
    Location
    London
    Posts
    304

    Default

    Yes, that's fine. I actually recommend using the hasOne property for one-to-one relationships:
    Code:
    class User {
        ...
        static hasOne = [ profile: Profile ]
        ...
    }

  7. #7
    Join Date
    Nov 2010
    Posts
    13

    Smile

    ok, I'll follow your recomendation for one-to-one relationships.

    Thanks for the help

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •