如何动态地将属性/字段添加到Grails中的域类?

时间:2012-09-20 08:47:34

标签: grails groovy gorm grails-domain-class

对于我目前正在处理的项目,我需要动态地向域类添加属性,并在以后将其保存在数据库中。通常,我需要一个附加到“普通”域类的键/值存储。遗憾的是,我无法使用NoSQL数据库(例如Redis)。

我的方法是通过在save()afterInsert中识别它们并将它们写入另一个表来处理afterUpdate上的其他属性 - 我宁愿不使用map属性在域类中,但附加“字段”表(以更好地支持搜索)。

我尝试使用 metaClass方法添加属性:

person.metaClass.middlename = "Biterius"
assert person.middlename == "Biterius"    // OK

这可行,我可以在afterInsert / afterUpdate方法中识别其他属性,但似乎我之后无法更改该值 - 即,以下内容不起作用:

person.middlename = "Tiberius"
assert person.middlename == "Tiberius"    // FAIL

然后我通过Expando类扩展Person类(直接(“Person extends Expando”)并通过抽象中间类(“Person extends AbstractPerson”和“AbstractPerson extends”)尝试了 Expando方法为Expando“))。

def person = new Person()
assert person in Person          // OK
assert person in AbstractPerson  // OK
assert person in Expando         // OK

两种变体都不起作用 - 我可以为任意“属性”赋值,但是没有存储值!

person.mynewproperty = "Tiberius"  // no MissingPropertyException is thrown 
println person.mynewproperty       // returns null

那么如何在运行时以编程方式向域类添加属性,在afterInsert或afterUpdate中更改它们并检索它们以便“手动”将它们存储在“Fields”表中?

或者我做错了什么?还有其他/更简单的方法吗?

2 个答案:

答案 0 :(得分:0)

将数据库变成“NoSQL”数据怎么样?

在我的一个项目中,我只使用String-property将地图存储为JSON-Object。 对于Groovy来说,在地图和JSON-Object之间进行转换并不是一个大问题。由于您可以像具有属性的对象一样访问地图,因此我发现此解决方案非常方便。

唯一的缺点:你必须提前计划你的String-property的大小......

更新:抱歉,您只是想知道您想支持搜索...

怎么样

class Person {
  ...
  static hasMany = [extProperties:KeyValue]
  ...
  def invokeMethod(String name, args) {
    if (name.startsWith('get')) {
       //an unknown properties's getter is called
    }
    //add same for setter
  }
}


class KeyValue {
  String key
  String value
}

我想这样的架构会给你所需的一切自由。即使没有hasMany,您也可以使用invokeMethod来处理外部表格...

getter和setter可以将您的值保存在瞬态字符串属性(static transients = ['myTransientProperty'])中。此属性应该在afterInsert /`afterUpdate'事件中可用。

答案 1 :(得分:0)

为什么不在域对象上创建字符串映射并手动存储额外数据?除非您存储复杂的数据,否则您应该能够从字符串中转换所需的任何内容。