自动保存失败的自定义插入和更新方法

时间:2010-10-12 17:01:24

标签: grails gorm grails-domain-class

我正在将Grails应用程序从Oracle移植到MySQL数据库。最初的Oracle版本是一个遗留数据库,它使用一些复杂的视图,利用Oracle没有的Oracle INSTEAD OF INSERT OR UPDATE功能。作为一种解决方法,我在Domain类上实现了Insert和Update方法,这些方法指向了这些类型的视图。例如,

class AdminUser {
    //...
    def update() {
        if(this.validate()) {
            Sql sql = Utils.getHibernateSql()

            sql.execute(
                "update table_x ...",
                [...]
            )

            sql.execute(
                "update table_y ...)",
                [...]
            )

            sql.execute(
                "update table_z ...",
                [...]
            )

            return true
        }

        return false
    }
    //...
}

以下是我正在遇到的问题的描述:

  1. 在服务方法中,我使用AdminUser.get
  2. 加载AdminUser实例
  3. 我修改了加载的实例并调用了update(),一切都很好
  4. 一旦服务方法完成执行,就会因为在实例上调用save而抛出异常。
  5. 如何防止在步骤(3)中发生神奇的保存(我最近在某处读到Grails会自动保存一个修改后的Domain类实例,该实例在退出服务方法时尚未保存,但我似乎无法看到现在找到该资源的链接)?

2 个答案:

答案 0 :(得分:2)

您将使用脏字段将已修改的实例保留在hibernate会话中。当hibernate会话被刷新时,它会尝试使用通常的save()方法再次保存对象。

一种解决方案是在手动保存更改后从休眠会话中丢弃对象。例如:

def update() {
    if(this.validate()) {
        Sql sql = Utils.getHibernateSql()

        sql.execute(
            "update table_z ...",
            [...]
        )

        ...

        this.discard()  // remove the object from the hibernate session
        return true
    }

此外,您可以将其添加到Config.groovy以要求明确保存对象:

hibernate.flush.mode="manual"

答案 1 :(得分:0)

如果使用read()而不是get(),则对象不会自动保持更改。您仍然可以显式调用save(),但OpenSessionInView拦截器刷新所有未保存的脏实例的标准行为将跳过使用read()加载的实例。