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.  [ 8 posts ] 
Author Message
 Post subject: Transaction question
PostPosted: Fri Apr 11, 2008 5:14 pm 
Newbie

Joined: Fri Feb 22, 2008 5:39 am
Posts: 14
Hello,

I'm a newbee to NHibernate and would like to get some advice on implementing transactions for my project. Here's what the code does :

1. I'm looping through a foreach statement to create my business objects (mapped in .hbm files)
2. After foreach statement all objects are persisted into the database with the following code

Code:
/// <summary>
        /// Saves an object and its persistent children.
        /// </summary>
        public void Save<T>(T item)
        {
            using (ISession session = m_SessionFactory.OpenSession())
            {
                using (session.BeginTransaction())
                {
                    session.SaveOrUpdate(item);
                    session.Transaction.Commit();
                }
            }
        }


Than, within the foreach statement I should update some values in my database with and SQL query

Code:
IQuery query = session.CreateSQLQuery("UPDATE somethin'");
query.ExecuteUpdate();


The problem is that if the session.SaveOrUpdate(item); fails the values updated in foreach statement with the SQL query are not rolled back.

Any idea on architecture issue ?

Thanks in advance for your help.

Hibernate version:2.0.50727

_________________
Thomas JASKULA - NODEVO
1, avenue du Général de Gaulle
60500 - Chantilly
+33 (0)3 44 26 36 72


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 14, 2008 4:46 pm 
Regular
Regular

Joined: Wed Aug 15, 2007 7:37 am
Posts: 73
If SaveOrUpdate fails it'll throw an exception; just don't run your query in that case.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 14, 2008 5:16 pm 
Newbie

Joined: Fri Feb 22, 2008 5:39 am
Posts: 14
I can only run my query in foreach statement which is before SaveOrUpdate.

_________________
Thomas JASKULA - NODEVO
1, avenue du Général de Gaulle
60500 - Chantilly
+33 (0)3 44 26 36 72


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 14, 2008 5:29 pm 
Regular
Regular

Joined: Wed Aug 15, 2007 7:37 am
Posts: 73
We've implemented a reference counted arrangement whereby you ask a wrapper for the session or a transaction, and tell the wrapper when you're done with it.

The first call to obtain a session or transaction causes it to get created; subsequent ones just return the same one but increase the appropriate reference counter. Similarly, releasing the session or transaction decreases the appropriate reference counter.

Only the final time the wrapper is asked to commit the transaction actually runs the commit. If anyone asks to rollback, subsequent commits will not be run.

So your code would look like (I don't know the exact structure, and you'd need error handling to make sure things got disposed):
Code:
try
{
  ISession session = sessionWrapper.GetSession();
  sessionWrapper.BeginTransaction();
  foreach ()
  {
      // Do your query
  }
  Save(item);
  sessionWrapper.CommitTransaction();
}
catch
{
  sessionWrapper.RollbackTransaction();
  throw;
}
finally
{
  sessionWrapper.ReleaseSession();
}


// In your save function
try
{
  ISession session = sessionWrapper.GetSession();
  sessionWrapper.BeginTransaction();
  session.SaveOrUpdate(item);
  sessionWrapper.CommitTransaction();
  sessionWrapper.ReleaseSession();
catch
{
  sessionWrapper.RollbackTransaction();
  throw;
}
finally
{
  sessionWrapper.ReleaseSession();
}


Note that (without adding another level of wrapping) you can't use using. Sorry that's a bit rough, but I hope the idea's clearish.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 15, 2008 3:58 am 
Beginner
Beginner

Joined: Fri Aug 10, 2007 3:34 am
Posts: 44
let me understand this right: you want to support multiple transactions and if one crashes you want to roll back all the previous ones?


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 15, 2008 10:20 am 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
I believe that the session wrapper behavior SteveMc is describing provides a transaction scope mechanism, similar to the TransactionScope class behavior in .NET 2.0. We also implemented this scoping mechanism.

This transaction scoping mechanism allows reusable methods to define the start and finish of a "transaction scope" rather than an actual transaction. If a transaction doesn't exist yet, the scope becomes a root and creates a transaction. If a transaction already exists, the scope becomes a child to the root scope that created the open transaction, and shares its transaction. When a scope finishes successfully, if it is a child, it simply sets a flag indicating it completed OK. If it is a root, it commits only if all children completed successfully, otherwise is rolls back.

Overall, it's a clean, reliable way to write code that uses transactions without having to deal with all the fuss over whether you need to create a new transaction or not, whether you should commit or not, etc.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 15, 2008 4:22 pm 
Beginner
Beginner

Joined: Fri Aug 10, 2007 3:34 am
Posts: 44
yup, the easiest soluion is to put all NH transaction code in a TransactionScope like this:

try
{
using (finalScope = new TransactionScope())
{
try
{
//all transactions here
}
catch (Exception exp)
{

}
finally
{

}
finalScope.Complete();
}
}
catch (TransactionAbortedException tae)//if a transaction fails
{
Console.WriteLine("Eroare salvare: The transaction failed!");
}
catch (TransactionInDoubtException tide)
{
}
finally
{

}

don't forget to start MS SQL service called distributed transactions service (or something like that)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Apr 15, 2008 6:36 pm 
Newbie

Joined: Fri Feb 22, 2008 5:39 am
Posts: 14
Thanks evryone for your help. I'll check your idea and keep you posted

SteveMc wrote:
We've implemented a reference counted arrangement whereby you ask a wrapper for the session or a transaction, and tell the wrapper when you're done with it...


If I understood well, I need to get rid of using statements and keep the sessionWrapper reference. I'll try to modify my code and check it.

Matrasinator wrote:
let me understand this right: you want to support multiple transactions and if one crashes you want to roll back all the previous ones?


Is it possible ?

Matrasinator wrote:
yup, the easiest soluion is to put all NH transaction code in a TransactionScope like this:


I'll try to find some information about it but for the moment I can't see how I need to modify my code to implement it.

_________________
Thomas JASKULA - NODEVO
1, avenue du Général de Gaulle
60500 - Chantilly
+33 (0)3 44 26 36 72


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 8 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.