对于我目前正在处理的项目,我需要动态地向域类添加属性,并在以后将其保存在数据库中。通常,我需要一个附加到“普通”域类的键/值存储。遗憾的是,我无法使用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”表中?
或者我做错了什么?还有其他/更简单的方法吗?
答案 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)
为什么不在域对象上创建字符串映射并手动存储额外数据?除非您存储复杂的数据,否则您应该能够从字符串中转换所需的任何内容。