-->
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.  [ 9 posts ] 
Author Message
 Post subject: transaction/architecture question
PostPosted: Thu Jun 30, 2005 10:33 am 
Newbie

Joined: Thu Jun 16, 2005 5:53 pm
Posts: 9
Hi,

Could someone tell me what the best approach is for spanning a transaction across multiple objects & methods?

I am building an asp.net app and am keeping the session in the HttpContext so my session is used by all of my service classes which is nice. But what if I want to span a transaction acorss two service objects, or what if I want to call one service object from another?

I guess my question is where is the best place to begin and commit transactions. I have a UI layer, service layer, domain layer and a dao layer. At the moment I have a base class in my dao layer that handles transactions for crud operations.

Thanks for any help/opinions.

Lachlan


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jun 30, 2005 11:48 am 
Hi,

I personally put my transaction controll as "high" up as possible - usually meaning in the GUI. I've done stuff like this before...

Code:
private void OnButtonClick(Object sender, EventArgs e)
{
  CustomerRepository repos = new CustomerRepository();
  InvoicingService invoicing = new InvoicingService();
  MailingService mailing = new MailingService();

  NHWrapper.BeginTransaction();

  Customer[] customers = repos.FindOverdue();

  //creates invoice objects and associates with customers
  Invoice[] invoices = invoicing.CreateInvoicesFor( customers );

  //sends emails, and also creates a
  //correspondence record against the invoices customer
  mailing.CreateAndSendEmailCorrespondenceFor( invoices );

  //this saves the customer (and will also cascade to save invoices and   correspondence)
  NHWrapper.SaveBatch( customers );

  NHWrapper.CommitTransaction();
}




Obviously you'd want to add exception handling etc, but this example should show how higher level transactional control allows you to make calls to several service classes, without worrying about transactions too much. Similarly, you could have service classes call each other, again without worrying about transactions.

One thing I personally like doing is preventing NHibernate from saving any changes without my saying so. This has it's risks (like reading stale data), but also means you only save when you really want to. To achieve this I set my Session SaveMode to Commit (sorry, not sure it that's the right term, don't have the code in front of me!)

Hope this helps

Tobin


Top
  
 
 Post subject:
PostPosted: Thu Jun 30, 2005 12:04 pm 
I suppose it depends on which parts of the application you want to know about the hierarchy.

Putting stuff in the GUI isn't always the best plan: consider the case where you always want to ensure that a number objects are saved. If you implement transaction control in your GUI, then you'll need to make sure that is ported to any other GUIs that you create. This is the problem with the ASP.Net model - each page is it's own controller, and so you're UI is tightly coupled (and mostly inseparatable from) the Controller.

Now, if you implemented a separate Controller then this should be in charge of your transactions. Your UI (aspx + aspx.(cs|vb)) would then act simply as conduits to the controller. An added layer, yes, but a nescessary one if you're going to be reusing your core logic. To simplify the model (and not having the headache of having to implement a full MVC framework), you can have your pages initiate the processing.

Obviously, if you're not going to reuse your code (possible in some cases, but I'd recommend this isn't the case in a security library), you can put your Transaction code into the code-behind. Just make sure you know the consequences.


Top
  
 
 Post subject:
PostPosted: Thu Jun 30, 2005 9:58 pm 
Regular
Regular

Joined: Mon May 16, 2005 1:35 am
Posts: 67
I agree with beardman. However, here's something I've been thinking about:

Sometimes even creating a separate Controller will not provide the maximum level of reusability. Consider a set of Controllers utilising a Service Facade layer to access business logic.

If the Service Facade relies on the Controllers to perform its transaction demarcation, then all clients of the Facade layer need to know when and how to create transactions on behalf of the Service Facade classes.

In order to maximise reuse, transaction demarcation should occur where it is needed. There must be a mechanism for enrolling new transactions in parent transactions so that transactionally-dependent business logic can be tied together into a single database transaction. This is the essence of reuse.

In this example therefore, the Service Facade would include its own transaction demarcation. In the case where a Page Controller would need to tie two separate services from the Service Facade into a single transaction, the Controller would create its own transaction and the Service Facade classes would be enlisted in this parent transaction.

One solution to this I have been considering implementing is to have a mechanism whereby classes can perform their own transaction demarcation and have those transactions transparently enrolled in a parent transaction if one exists and if they so desire.

A good model for this is the TransactionScope class in the System.Transactions namespace in .NET 2.0. However in this case, there would be an NHibernateScope class, which would hold its NHibernate session context information in the CallContext.

NHibernate transaction demarcation would occur in the following way:

using (NHibernateScope scope = new NHibernateScope(Transactions.Required)
{
ISession session = scope.NHSession;

// Do your transactional work

scope.Consistent = true;
}

Another advantage to this approach is that classes using the NHibernateScope object will operate in both an ASP.NET and a WinForms environment. Current thinking regarding ASP.NET applications that I have been reading indicate that such applications should leverage the HttpContext object to hold the NHibernate session. The issue here is that classes dependent on the HttpContext object cannot then be used in any other environment.

I'd be very interested in getting everyone's thoughts on this.

Baggins


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 01, 2005 5:15 am 
Newbie

Joined: Thu Jun 16, 2005 5:53 pm
Posts: 9
Thank you for your replies, this has given me some things to think about.

In my case the application is a website and multiple ui layers would be unlikely, so I would rather not implement a full blown mvc framework at this stage.

Baggins I like the sound of your idea, being able to handle transactions transparently in the service layer would be ideal. Since I don't mind having my code tied to asp.net I could achieve this in a similar way to the session handling using the HttpContext.

In the simplest case I could store the NHibernate transaction in the HttpContext and use the same transaction for any database activity throughout the entire request and simply commit the transaction at the end of the request if it exists. I currently have an HttpModule that handles sessions so putting it in there may be ok. In this case every request would only have one transaction, but I think that


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 01, 2005 9:19 pm 
I'd agree with beardman too, especially if I was going to have more than one GUI. I'd probably find myself factoring operations that I do in the GUI into another controller layer, which handles transaction control. Despite the fact that ASP.NET pages *are* controllers, they're not exactly reusable in different contexts :)

Transaction Control
When I started playing with NHibernate, I dug around quite a bit to find some ideas for transaction control. Baggins idea of transparent control is quite appealing. In fact, I've come across it a few times in my virtual travels. Also, Clifton Nock discusses it in his book Data Access Patterns...

http://www.amazon.co.uk/exec/obidos/tg/detail/-/0131401572/ref=pd_sxp_f/026-7659574-1432429?v=glance&s=books

From what I understand, this "transparent" control is called *declarative* transaction demarcation, and is present in quite a few of the Java frameworks (Spring, JBoss etc). In .NET, you might have something that looks like this...

public class ProductService
{
[Transaction.Required]
public void DoSomething(Product product)
{
}
}

As far as I remember, Spring.NET were going to implement such transaction control in their framework. Didn't see anything in their docs though, so perhaps it's still in the pipeline.

Session Scope
My NHibernate wrapper hides the fact that HttpContext is being used, and works equally well in a WinForms environment. The trick I use is to determine if their is a HttpContext available, and if not then switch to a Thread Local Session strategy. This means that in an ASP.NET environment, the HttpContext is automatically used, and in a WinForms environment, thread local storage is automatically used. All this is hidden from the client.



[/b]


Top
  
 
 Post subject:
PostPosted: Fri Jul 01, 2005 9:23 pm 
Woops, forgot to enter my name in the above post. I really should set up an account!...

Tobin


Top
  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 6:37 am 
Expert
Expert

Joined: Tue Aug 23, 2005 5:52 am
Posts: 335
Hi Baggins,

Have you done any further investigation along these lines? I'm really interested in implementing something of my own along these lines and wondered whether you've tried something yourself.

Cheers,

Symon.


Top
 Profile  
 
 Post subject:
PostPosted: Mon Apr 10, 2006 2:24 pm 
Expert
Expert

Joined: Fri Oct 28, 2005 5:38 pm
Posts: 390
Location: Cedarburg, WI
Some time ago Baggins replied to a similar post, recommending the creation of an NHibernateTransactionScope class that implements the same pattern as System.Transactions.TransactionScope. We thought it was a great idea and created one. Now we don't have to worry about who creates the transaction, because the vast majority of our code uses the default scope behavior (join the ambient transaction if present, otherwise create one that becomes the ambient transaction).


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