Объект домена, ссылающийся на справочную таблицу в Grails GORM

У меня есть объект домена с именем Пользователь:

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

У меня также есть объект почтового индекса:

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

Таблицу почтовых индексов никогда не следует изменять, поскольку она содержит предварительно заполненные статические справочные данные.

Пользователь принадлежит к одному почтовому индексу. Пользователь вводит почтовый индекс как часть создания пользователя.

Как мне смоделировать отношения объектов предметной области? Я хотел бы убедиться, что GORM не пытается обновить почтовые индексы. Я хотел бы убедиться, что пользователь вводит только действительные номера почтового индекса. (которые находятся в таблице почтовых индексов) Как настроить ограничения для объекта «Пользователь»? В контроллере делаю следующее:

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

Как установить правильный почтовый индекс на объекте?


person Tihom    schedule 24.10.2010    source источник


Ответы (3)


Вы бы не разрешили GORM управлять свойством zip (и запретили GORM делать это на втором этапе) вообще.

Об этом говорит и подход mfloryan; однако его подход не разделяет проблемы должным образом (парадигма разделения проблем): в шаблоне MVC (модель-представление-контроллер) это не задача контроллеров для «моделирования» модели данных, но это задача уровня доступа к данным (который - в случае GORM - сами классы предметной области).

Таким образом, класс User будет реализован так:

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

Обратите внимание на метод retrieveZipCode(). Он не называется getZipCode(), так как в противном случае Hibernate выдал бы исключение об «отсутствующем методе установки». Вы также можете поэкспериментировать с добавлением свойства zipCode, метода getZipCode() (который ничего не делает или, напротив, выдает исключение) и добавления свойства zipCode к определению transinients. - Все это (в любой комбинации) не будет работать.

Также обратите внимание на определение constraints: оно совпадает, когда zip состоит ровно из пяти цифр. (Я полагаю, что это формат почтовых индексов в США.) Он также должен убедиться, что база данных содержит запись для почтового индекса пользователя (синтаксис не проверен).

Я немного изменил класс ZipCode (частично, чтобы избежать ошибки компиляции):

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

И, наконец, интеграционный тест:

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()
    }
}

Спасибо

person robbbert    schedule 24.10.2010

Это больше похоже на проблему пользовательского интерфейса. Выполните поиск объекта Zipcode в контроллере и установите объект, расположенный у пользователя. В противном случае я не понимаю, как Zipcode мог быть изменен при создании пользователя.

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

Вы должны включить некоторую логику проверки (если почтовый индекс неверен), а также подумать о переименовании params.zip в params.userProvidedZip или что-то в этом роде.

person mfloryan    schedule 24.10.2010

использовать обратный вызов события домена

   transient beforeUpdate = { 
      // check to make sure that the zip code value remains the same
      // and is never changed... 
   } 
person Aaron Saunders    schedule 24.10.2010
comment
Я думал об этом. Это сработает только в том случае, если я создам временный параметр с именем zipCodeString в объекте домена пользователя. В методе beforeUpdate мне пришлось бы искать ZipCode и устанавливать zipCode с результатом запроса. Это то, что вы имели в виду? - person Tihom; 24.10.2010
comment
@Tihom, это был подход, который я предлагал - person Aaron Saunders; 24.10.2010
comment
Знаете ли вы, как я могу запретить GORM обновлять таблицу почтовых индексов? - person Tihom; 24.10.2010
comment
@Tihom никогда не пробовал, но вы можете проделать тот же трюк с событием beforeUpdate и просто выдать исключение - person Aaron Saunders; 25.10.2010