Grails数据绑定:使用映射创建抽象类的实例
与我的上一个问题()类似,我想对一个包含具有hasMany关系的抽象类集合的类使用数据绑定,但在本例中,我使用的不是列表,而是映射 我创建了一个集成测试失败的smalll项目,以显示问题,运行时使用:Grails数据绑定:使用映射创建抽象类的实例,grails,Grails,与我的上一个问题()类似,我想对一个包含具有hasMany关系的抽象类集合的类使用数据绑定,但在本例中,我使用的不是列表,而是映射 我创建了一个集成测试失败的smalll项目,以显示问题,运行时使用: grails test-app -integration -echoOut DataBinding 无论如何,我将在这里通过描述类和测试来解释这个问题: class LocalizableContent { Map contentByLocale = [:].withDefault { l
grails test-app -integration -echoOut DataBinding
无论如何,我将在这里通过描述类和测试来解释这个问题:
class LocalizableContent {
Map contentByLocale = [:].withDefault { locale -> new Text() }
static hasMany = [ contentByLocale : Content ]
}
abstract class Content {
static belongsTo = [ localizableContent : LocalizableContent ]
static constraints = {
localizableContent nullable:true
}
}
class Text extends Content {
String text
}
如您所见,我已经在使用withDefault技巧,但Grails/Spring显然没有调用它(我甚至尝试在默认闭包中抛出一个异常来验证代码是否未执行)
为了测试,我还创建了一个LocalizableContentController,它是空的。在所有这些情况下,以下集成测试失败:
void testMapDatabinding() {
def rawParams = [ 'contentByLocale[en].text': 'Content' ]
def controller = new LocalizableContentController()
controller.request.addParameters(rawParams)
controller.request.setAttribute(GrailsApplicationAttributes.CONTROLLER, controller)
def localizableContent = new LocalizableContent(controller.params)
assert localizableContent?.contentByLocale['en']?.text == 'Content'
}
它说localizableContent.contentByLocale是一个看起来像['en':null]的映射,因此显然数据绑定正在理解映射语法并尝试为'en'键创建一个条目。但是没有首先尝试获取该键的条目,因为没有调用withDefault
下面的一个测试测试withDefault工作正常,并且通过:
void testMapByDefaultWithNoDatabinding() {
assert new LocalizableContent().contentByLocale['en']?.getClass() == Text
}
这里我缺少什么?不过是一种模式,当您面对未知的键时,它可以提供有效的值。例如,考虑下面的用例:
def map = [:].withDefault{k->
println k //Should print 'a'
10
}
map.test = 32
assert map.test == 32
assert map.a == 10
它以未知键作为参数,您不能向它传递任何值,这是一种逻辑,因为它提供了一个默认值,而不是提供的值
在您的情况下,如果将值设置为Text
,则数据绑定将起作用,如:
Map contentByLocale = [:].withDefault { locale ->
//locale is the key. 'en' in this case
new Text(locale: locale, text: 'Content')
}
如果将文本类定义为
class Text extends Content{
String locale
String text
}
我完全理解Groovy提供的withDefault技术:),事实上,我希望能够向它传递一个密钥,我只是不使用它,所以示例不会变得太复杂。LocalizableContent按区域设置存储内容,因此内容中没有区域设置,它只是在LocalizableContent中按区域设置索引。您提供的代码并没有真正改变任何东西,因为这里的问题是根本没有调用withDefault闭包(我猜Spring/Grails数据绑定在尝试插入新的条目之前并没有在映射中查找现有条目)。