grails - 可以将 DomainObject 添加为 CommandObject 的属性吗?
问题描述
我使用 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
然后域对象内部的 User 对象将从数据库中加载 id=3,并且 user.name 属性将被更改。User 对象现在被标记为脏并已添加到会话中。如果您碰巧执行了一些调用刷新的代码(或将 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 的示例。它似乎总是基本类型。