Stephen Swensen
Stephen Swensen

Reputation: 22297

Custom Insert and Update methods defeated by automatic Save

I am porting a Grails application from Oracle to MySQL database. The original Oracle version is a legacy database which uses a few complex Views leveraging Oracle's INSTEAD OF INSERT OR UPDATE feature which MySQL doesn't have. As a workaround I have implement Insert and Update methods on the Domain classes which point to these kinds of Views. For example,

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
    }
    //...
}

Here is a description of the problem I am running into at the moment:

  1. Within a service method I load an instance of AdminUser using AdminUser.get
  2. I modify the loaded instance and call update(), all appears well
  3. Once the service method finishes executing an exception is thrown due to something calling save on the instance.

How can I prevent the magical save happening in step (3) (I recently read somewhere that Grails will automatically save a modified Domain class instance which hasn't yet been saved upon exiting a service method, but I can't seem to find the link to that resource right now)?

Upvotes: 0

Views: 1343

Answers (2)

Burt Beckwith
Burt Beckwith

Reputation: 75671

If you use read() instead of get(), then the object will not auto-persist changes. You can still call save() explicitly, but the standard behavior where the OpenSessionInView interceptor flushes all unsaved dirty instances will skip the instances loaded with read().

Upvotes: 0

ataylor
ataylor

Reputation: 66059

You're leaving the modified instance in the hibernate session with dirty fields. When the hibernate session gets flushed, it will try to save the object again with the usual save() method.

One solution would be to discard your object from the hibernate session after you've manually saved the changes. For example:

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
    }

In addition, you can add this to your Config.groovy to require that objects be saved explicitly:

hibernate.flush.mode="manual"

Upvotes: 2

Related Questions