开发者

Domain object referring to a reference table in Grails GORM

开发者 https://www.devze.com 2023-01-21 00:03 出处:网络
I have a domain object called User: class User{ String username; String firstName; String lastName; Zipcode zip;

I have a domain object called User:

class User{
  String username;
  String firstName;
  String lastName;
  Zipcode zip;
}

I also have a Zip Code object:

class Zipcode {
  String zip;
  String city;
  String state;
  Float lat;
  Float long;
}

The zipcode table should never be modified as it contains static reference data prepopulated

A user belon开发者_运维百科gs to one zipcode. The user enters the zipcode as part of the User creation.

How should I model the domain objects relationship? I would like like to make sure that GORM does not attempt to update zipcodes. I would like to make sure that the user only enters valid zipcode numbers. (Which are found in the zipcode table) How do I configure the constraints on the User object? In the controller, I do the following:

def userInstance = new User(params) // where params are form values

How do I set the proper zipcode on the object?


You would not let GORM manage the zip property (and restrict GORM from doing so at a second stage), at all.

That's what mfloryan's approach tells, too; however, his approach doesn't separate concerns, properly (separation of concerns paradigm): In the MVC (Model-View-Controller) pattern, it's not the controllers' task to "model" the data model, but it's the task of the data access layer (which is - in case of GORM - the domain classes theirselves).

Thus, the User class would be implemented like that:

class User {
    String userName
    String firstName
    String lastName
    String zip

    ZipCode retrieveZipCode() {
        ZipCode.findByZip(zip)
    }

static constraints = {
    zip nullable: false, blank: false, matches: /^\d{5}/,
    /* not tested at my machine: */
    validator: {
        if(!retrieveZipCode(it)) {
            return false
        }
    }
}
}

Note the retrieveZipCode() method. It's not called getZipCode() as, otherwise, Hibernate would throw an exception about a "missing setter method". You can also experiment with adding a zipCode property, a getZipCode() method (that does nothing or, alternatively, throws an exception), and adding the zipCode property to the transinients definition. - Everything of this (in any combination) will not work.

Also note the constraints definition: It matches when the zip consists of exactly five digits. (I believe that's the format of ZIP codes there in the USA.) It should also make sure that the database contains an entry for the user's ZIP code (syntax not tested).

I've changed the ZipCode class slightly (partly, to avoid a compilation error):

class ZipCode {
    String zip;
    String city;
    String state;
    Float latitude;
    Float longitude;
}

And finally, there's an integration test:

class UserTests extends GroovyTestCase {
    def testUserCreation() {
        User user = new User(
            userName: "foo", firstName: "bar", 
            lastName: "baz", zip: "12345")
        assert user.validate()
        assert user.retrieveZipCode()
        user.save()
    }
}

Thanks


This sounds like more of an UI issue. Do a Zipcode object lookup in the controller and set the the object located on the user. Otherwise, I can't see how a Zipcode could have been altered upon creation of a user.

save = {
  params.zip.id = Zipcode.findByZip(params.zip)
  def userInstance = new User(params)
}

or

save = {
  def userInstance = new User(params)
  userInstance.zip = Zipcode.findByZip(params.zip) 
}

You should include some validation logic (if the zip is incorrect) and also consider renaming params.zip to params.userProvidedZip or something like that.


use Domain event callback

   transient beforeUpdate = { 
      // check to make sure that the zip code value remains the same
      // and is never changed... 
   } 
0

精彩评论

暂无评论...
验证码 换一张
取 消