2013-02-25 4 views
1

Я пытаюсь найти способ добавления динамических полей в класс домена grails. Я нашел динамический класс домена, основанный на статье Берт, но это слишком много для наших нужд.Добавление динамических полей в объект домена в Grails

Предположил есть класс домена человека:

class Person extends DynamicExtendableDomainObject { 
    String firstName 
    String lastName 

    static constraints = { 
     firstName(nullable: false, blank: false, maxSize: 50) 
     lastName(nullable: false, blank: false) 
    } 
} 

Теперь клиент хочет также иметь поле BirthDate в этом. Используя какой-то инструмент управления, он добавляет это дополнительное поле в базу данных.

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

Теперь мы реализовали класс DynamicExtendableDomainObject, наследуемый классом Person. Это добавляет настраиваемое поле для каждого класса Domain, наследующего от него, для хранения динамических свойств в нем JSON (вроде KiokuDB в Perl хранит их).

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

Так что на клиенте мы могли бы использовать строительный лес и человек будет выводить ПгвЬЫате, LastName, BirthDate на клиенте б подмостей будет выводить ПгвЬЫате, ФАМИЛИЯ, ОТЧЕСТВО.

Сохранение свойств будет осуществляться с использованием saveinterceptor, чтобы сериализовать эти свойства в JSON и сохранить их в специальном поле.

Но мы еще не нашли способ динамически добавлять эти свойства JSON в класс домена во время выполнения. Есть ли хороший способ справиться с этим? И если да, то как это лучше всего реализовать?

+0

Я не уверен, если я понял вашу проблему, но не может вы просто использовали карту с дополнительным значений на каждую запись Person, вместо того, чтобы возиться с классом домена? – elias

+0

У вас есть пример где-нибудь, используя решение карты (или плагин, который использует этот метод, чтобы я мог взглянуть на него)? Как работает решение карты с проверкой? Как хранит карты gorm/hibernate? – PWFraley

+0

См. Http://grails.org/doc/latest/guide/GORM.html#sets,ListsAndMaps Hibernate создаст другую таблицу для хранения значений карты, что-то вроде 'person_MapName'. Я не уверен, как пройти проверку, однако вам придется реализовать пользовательский валидатор. – elias

ответ

2

Вы можете попробовать добавить свойства во время выполнения в DomainClass типа DynamicExtendableDomainObject путем расширения GetProperty(), SetProperty(), setProperties() в Метакласс, а затем использовать BeforeUpdate(), beforeInsert() и постнагрузки() для зацепиться за упорство.

Например, в Bootstrap (или услуги):

def yourDynamicFieldDefinitionService 

for(GrailsClass c in grailsApplication.getDomainClasses()){ 
    if(DynamicExtendableDomainObject.isAssignableFrom(c.clazz)){ 
     Set extendedFields = yourDynamicFieldDefinitionService.getFieldsFor(c.clazz) 

     //getProperty() 
     c.clazz.metaClass.getProperty = { String propertyName -> 
      def result 
      if(extendedFields.contains(propertyName)){ 
       result = delegate.getExtendedField(propertyName) 
      } else { 
       def metaProperty = c.clazz.metaClass.getMetaProperty(propertyName) 
       if(metaProperty) result = metaProperty.getProperty(delegate) 
      } 
      result 
     } 

     //setProperty() 
     c.clazz.metaClass.setProperty = { propertyName , propertyValue -> 
        if(extendedFields.contains(propertyName)){ 
         delegate.setExtendedField(propertyName, propertyValue) 
         delegate.blobVersionNumber += 1 
        } else { 
         def metaProperty = c.clazz.metaClass.getMetaProperty(propertyName) 
         if(metaProperty) metaProperty.setProperty(delegate, propertyValue) 
        } 
       } 

     //setProperties() 
       def origSetProperties = c.clazz.metaClass.getMetaMethod('setProperties',List) 
       c.clazz.metaClass.setProperties = { def properties -> 
        for(String fieldName in extendedFields){ 
         if(properties."${fieldName}"){ 
          delegate."${fieldName}" = properties."${fieldName}" 
         } 
        } 
        origSetProperties.invoke(delegate,properties) 
       } 
    } 
} 

с

abstract DynamicExtendableDomainObject { 
    String yourBlobField 
    Long blobVersionNumber //field to signal hibernate that the instance is 'dirty' 

    Object getExtendedField(String fieldName){ 
     ... 
    } 

    void setExtendedField(String fieldName, Object value){ 
     ... 
    } 

    def afterLoad(){ 
     //fill your transient storage to support getExtendedField + setExtendedField 
    } 

    def beforeUpdate(){ 
     //serialize your transient storage to yourBlobField 
    } 

    def beforeInsert(){ 
     //serialize your transient storage to yourBlobField 
    } 
} 
+0

Почему используется 'delegate. '$ {FieldName}" 'вместо' owner.' $ {FieldName} "'? благодаря –