2

So in my database, I have 3 rows, two rows have defaultFlag as 0 and one is set to 1, now in my processing am updating defaultProperty of one object to 1 from 0 but am not saving this object yet.

Before saving I need to query database and find if any row has defaultFlag set or not, there would be only 1 default set.

So before doing update am running query to find if default is set and i get 2 values out, note here if i go and check in db then there is only 1 row with default set but query gives me two result because this.object default property has changed from 0 to 1 but note that this object is not yet saved in database.

I am really confused here as to why hibernate query is returning 2 when there is one row with default set in database and other object whose default property has changed but it is not saved.

Any thoughts would be helpful. I can provide query if need be.

Update

Following suggestions, I added session.clear() to before running the query.

session.clear();
String sql = "SELECT * FROM BANKACCOUNTS WHERE PARTYID = :partyId AND CURRENCYID = :currencySymbol AND ISDEFAULTBANKACCOUNT= :defaultbankAccount";
                SQLQuery q = session.createSQLQuery(sql);
                q.addEntity(BankAccount.class);
                q.setParameter("partyId", partyId);
                q.setParameter("currencySymbol", currencySymbol);
                q.setParameter("defaultbankAccount", 1);
                return q.uniqueResult();

and it returns 1 row in result as expected but now am getting

nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session exception

3 Answers 3

3

Either query which row has the "default flag" set before you start changing it, or query for a list of rows with default flag set & clear all except the one you're trying to set.

Very easy, stop mucking about with your "brittle" current approach which will break in the face of concurrency or if data is ever in an inconsistent state. Use a reliable approach instead, which will always set the data to a valid state.

protected void makeAccountDefault (BankAccount acc) {

    // find & clear any existing 'Default Accounts', other than specified.
    //
    String sql = "SELECT * FROM BANKACCOUNTS WHERE PARTYID = :partyId AND CURRENCYID = :currencySymbol AND ISDEFAULTBANKACCOUNT= :defaultbankAccount";
    SQLQuery q = session.createSQLQuery(sql);
    q.addEntity(BankAccount.class);
    q.setParameter("partyId", partyId);
    q.setParameter("currencySymbol", currencySymbol);
    q.setParameter("defaultbankAccount", 1);
    //
    List<BackAccount> existingDefaults = q.list();
    for (BankAccount existing : existingDefaults) {
        if (! existing.equals( acc))
            existing.setDefaultBankAccount( false);
    }

    // set the specified Account as Default.
    acc.setDefaultBankAccount( true);

    // done.
}

This is how you write proper code, do it simple & reliable. Never make or depend on weak assumptions about the reliability of data or internal state, always read & process "beforehand state" before you do the operation, just implement your code clean & right and it will serve you well.

Sign up to request clarification or add additional context in comments.

Comments

1

I think that your second query won't be executed at all because the entity is already in the first level cache.

As your transaction is not yet commited, you don't see the changes in the underlying database.

(this is only a guess)

7 Comments

yeah but then when am doing query to get rows with defaultFlag set then it should return me what i have in database, that is, only one two and not two because second one is only in memory and not saved.
As @aumand says, Hibernate is resolving the Hibernate query using its cache. This is the appropriate behavior. If you tried a the Hibernate query in a different session you'd get the same results as you're seeing when you query the DB directly.
@MikeThomas can you point me to some examples of this...want to understand more about what's is happening behind the scenes.
stackoverflow.com/questions/337072/… maybe this example is the one you need: image an instance of an entity. During ONE session, you update one field 10 times. Instead of performing 10 queries, hibernate caches an instance in the first level cache and during commit it basically persists the entity ONCE (i.e one query instead of 10).
My suggestion is for you to read "Hibernate in Action". It is the bible for Hibernate use. I'll explain the situation one other way, though (somewhat oversimplified). Imagine you're at the database command line, and you have started a transaction. If you update the database, and then query before your commit, do you see your update? The answer is "yes". Does someone else with a different connection see your change? No. Not until you commit your change. Hibernate does a similar thing, but in memory.
|
0

That's only a guess because you're not giving many details, but I suppose that you perform your myObject.setMyDefaultProperty(1) while your session is open.

In this case, be careful that you don't need to actually perform a session.update(myObject) to save the change. It is the nominal case when database update is transparently done by hibernate.

So, in fact, I think that your change is saved... (but not commited, of course, thus not seen when you check in db)

To verify this, you should enable the hibernate.show_sql option. You will see if an Update statement is triggered (I advise to always enable this option in development phase anyway)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.