我正在使用grails CommandObject存储搜索页面的所有信息。像
class SomeSearchCommand {
User user
...
Integer max=100
Integer offset=0
}
然后在控制器中
class SomeThingController {
def search(SomeSearchCommand c) {
// build a query based SomeSearchCommand
Something.where {
if (c.user) user==c.user
...
}.list(max: c.max, offset: c.offset)
}
}
这似乎效果很好,并且当您使用调用操作时
/someThing/search?user=3&offset=100
它找到属于用户3的所有“ SomeThing”对象。
但是在玩代码时,我发现如果将URL更改为
/someThing/search?user.id=3&user.name=ichangedyourname&offset=100
然后,将从数据库中将id = 3加载到域对象内部的User对象,并更改user.name属性。用户对象现在被标记为脏对象,并已添加到会话中。如果您碰巧执行一些调用刷新的代码(或将flushMode设置为Auto),则对用户对象的更改将保留。
我通过在用户对象周围添加@BindUsing找到了解决方法。这似乎禁用了对用户对象的深度绑定,并且仅允许通过user
而不是user.id
的参数进行绑定
class SomeSearchCommand {
@BindUsing({obj, source ->
if (source['user'] instanceOf User) return source['user']
if (source['user'] instanceOf serializable) return User.get(source['user'])
})
User user
...
Integer max=100
Integer offset=0
}
另一种解决方法是不使用CommandObject中的用户域对象。
class SomeSearchCommand {
String userId
User getUser() {
return User.get(userId)
}
...
Integer max=100
Integer offset=0
}
这意味着URL请求必须更改为/some/search?userId=3&offset=100
但是user
仍然是命令对象的属性,它返回键入的对象。
我首先使用grails 2.3.11(将flushMode设置为auto)注意到了这一点,因此内部域对象始终被写入数据库。 在2.4之后的grails版本中,刷新模式设置为“手动”,因此修改后的域对象仅在刷新会话时持久存在。
我没有在grails文档中看到有关将domainObject放在commandObject内的任何示例。它似乎总是基本类型。