These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 
Author Message
 Post subject: A problem with business logic and NonUniqueObjectException
PostPosted: Sat Apr 07, 2007 6:13 pm 
Newbie

Joined: Thu Apr 05, 2007 11:11 pm
Posts: 4
Hello All,

I'm working on a simple budget web-app and have run into a problem with NonUniqueObjectException. Here's the basic setup:

Step 1: I've got an Account (for example, a "Checking" account) with a pre-existing balance of $100.00. I add a transaction (for example, a "groceries" transaction) of $25.00. That action affects my Account balance and my account balance is now $75.00.

Step 2: A few days later I come back to my budgeting program and realize I've mistakenly entered $25.00 for my transaction when I meant to enter $50.00. So I click on edit transaction, put the new value of $50.00 in, and click save. Then the program blows up with a "NonUniqueObjectException" exception and my changes are unsaved due to the transaction rollback.

Now I have a servlet front end layer which is making calles to a services layer which is making calls to a DAO layer. The database transaction demarcation is done through Spring on the services layer methods. So a new database transaction is started when the front end calls a service method and the transaction is committed when the service method returns without exception.

The code for addTransaction() in my services layer executed for step #1 above works just fine. The pseudo-code for that method is thus:

Code:
addTransaction(Transaction transaction)
{
    Account account = transaction.getAccount();
    account.setBalance(account.getBalance() - transaction.getAmount());
    AccountServices.updateAccount(account);
    TransactionDAO.addTransaction(transaction);
}

TransactionDAO.addTransaction(Transaction transaction)
{
   this.hibernateTemplate.save(transaction);
}




But things blow up and get complicated with updateTransaction() for step #2 above:

Code:
updateTransaction(Transaction transaction)
{
    //get the currently saved version of the transaction out of the db
    //   so we can remove the old transaction amount from the
    //   associated account

    Transaction oldTransaction = transactionDAO.getTransaction(transaction.getId());

    Account account = oldTransaction.getAccount();
    account.setBalance(account.getBalance() + oldTransaction.getAmount());
    AccountServices.updateAccount(account);

    //now that we've effectively removed the old transaction amount
    //  from the account's balance, we need to add the update transaction
    //  amount back into whichever account it's interested in


   // Note that the account associated with the transaction could
   // have changed so we can't rely on the account given from
   // oldTransaction..


    account = transaction.getAccount();
    account.setBalance(account.getBalance() - transaction.getAmount());
    AccountServices.updateAccount(account);
    TransactionDAO.updateTransaction(transaction);
}

TransactionDAO.updateTransaction(Transaction transaction)
{
   this.hibernateTemplate.update(transaction);
}



That of course throws a NonUniqueObjectException on the updateTransaction() line, if one's not thrown on the second updateAccount() call due to multiple versions of an account isntance floating around.

I've looked at the common problems FAQ answer for this problem (http://www.hibernate.org/116.html#A8), but the suggestion there is that i should call saveorupdate before doing anything else. Obviously that's not possible in this case because that would save over the original transaction amount I'm trying to get at.

I also tried to do this:

Code:
TransactionDAO.updateTransaction(Transaction transaction)
{
   Transaction mergedTransaction = this.hibernateTemplate.merge(transaction);
   this.hibernateTemplate.update(mergedTransaction );
}


but that also had the same nonunique exception :/

I can't figure out a sane way to address this problem with a single "Transaction" object floating around. I really need the old version of the transaction to make my business logic straightforward in that method above, but this NonUnique exception is forcing me to rethink my logic in several ways that seem screwy to me. It seems I should be able to tell the hibernatesession to "forget" about the "oldTransaction" object above and still be able to have my database transaction rollback options open if something goes wrong. If i flush() on the hibernate session will that screw up my chances at a database transaction rollback? If i flush() will that get rid of the session's knowledge of the "oldTransaction" object? Is there something else I should do?

How would you guys suggest solving this problem? Is there something simple I'm missing in hibernate mapping or configuration or usage that'd remedy this problem? Perhaps there's even a way to make hibernate handle my data integrity in this simple budgetting account balance -> transaction amounts case?

[/code]


Top
 Profile  
 
 Post subject:
PostPosted: Sat Apr 07, 2007 6:30 pm 
Newbie

Joined: Thu Apr 05, 2007 11:11 pm
Posts: 4
My bad. I just tried the merge solution again and noticed that the NonUnique exception was complaining about my Account objects after I fixed up the Transaction objects dao, so here's the solution:

Code:
AccountDAO.updateAccount(Account account)
{
   Account mergedAccount = this.hibernateTemplate.merge(account);
   this.hibernateTemplate.update(mergedAccount );
}

TransactionDAO.updateTransaction(Transaction transaction)
{
   Transaction mergedTransaction = this.hibernateTemplate.merge(transaction);
   this.hibernateTemplate.update(mergedTransaction );
}


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 2 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.