2

I am trying to upgrade a Grails app from 1.0.3 to 1.3.7 and ran into the exception:

 object references an unsaved transient instance - save the transient instance before flushing:

I am not doing any saves in the code that triggers. It is in the following code

public static Season getCurrentSeason() {
        String yearString = ConfigurationHolder.config.year
        assert yearString != null: "need to configure season"
        int year = Integer.parseInt(yearString)

        Affiliation nfl = Affiliation.nfl;
        return Season.findBySeasonKeyAndLeague(year, nfl)
    }

The call to Affiliation.nfl is:

public static Affiliation getNfl() {
           if (cacheNFL == null) {
            String key = ConfigurationHolder.config.nfl
            cacheNFL = Affiliation.findByKey(key)
        }
        return cacheNFL;
    }

If I removed the cacheNFL and make it do a real fetch each time, the code works. My questions are:

  • Why did this work before? It seems like making a fetch with a cached object that isn't part of the current Hibernate query (which I am, perhaps incorrectly, assuming is the problem) would never be supported.
  • Is there anyway around this problem aside from making a fetch to the database?
  • How can I tell if I am hitting the database or going to a Hibernate cache (I don't know much about Hibernate). Is there output that can show me?
Kara
  • 6,115
  • 16
  • 50
  • 57
skaz
  • 21,962
  • 20
  • 69
  • 98

1 Answers1

6
  1. It's findBy* that triggers a flush() - every Criteria flushes any object that can be potentially returned by that Criteria. This is done in order to ensure that Criteria returns all the matching objects. Looks like this logic was introduced in 1.1.

  2. Try fetching the object in Affiliation.withNewSession{ }. Or, better, fetch it before you begin your current transaction/in the beginning of transaction, before the flush()ed objects get dirty.

  3. Enable Grails sql logging: How to log sql in grails 1.3.7

Community
  • 1
  • 1
Victor Sergienko
  • 13,115
  • 3
  • 57
  • 91
  • 1
    Thanks for your input. I don't really know what you mean in your first and second points - I'm pretty new to this. So when I pass in my cached Affiliation object it flushes it, which calls a save essentially? Can you elaborate more on your points? Thank you so much for your help. – skaz Jun 21 '11 at 18:20
  • 1. It's not a cached entity, but a cache ititialization (your `Affiliation.findByKey()`) that causes `flush()`. `flush()` is, yes, like a `save()`, writes the changes to database. Only that it is not committed - it will be rolled back automatically if you `discard()` it or don't actually `save()` anything. (I might be wrong about Hibernate internals here, but it's the idea) – Victor Sergienko Jun 22 '11 at 13:34
  • 2. In order not to `flush()` your current Hibernate session (http://www.coderanch.com/t/218534/ORM/java/Difference-between-commit-flush-Hibernate), you can run a code in a different `Session` - it's what `.withNewSession{ }` does. Though, you won't be able to save/connect an object from a different session, until you `attach()` (http://grails.org/doc/latest/ref/Domain%20Classes/attach.html) it to your current session. – Victor Sergienko Jun 22 '11 at 13:42