首页 > 解决方案 > 可以将 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 的示例。它似乎总是基本类型。

标签: grails

解决方案


推荐阅读