Posts
820
Comments
681
Trackbacks
1
ASP.NET, DataContext, and LINQ to SQL: Business Process Model

In my previous post, I pointed out a good article by Rick Strahl on different ways to handle DataContext management and mentioned that I used his 'Business Object' method.  This actually isn't quite accurate, so let me expand on that a little bit.

I'll use a standard e-Commerce site as an example.  If you think about most of the data access that is required when creating an eCom site, there is little about the DataContext that you really need to worry about.  Product lists, navigation elements, search results, and other items are essentially read-only, so you can use a DataContext and get rid of it.

Even things like user profiles or shopping carts do not require you to carry around a DataContext.  If you need to add/remove something to a shopping cart, it is much better to recreate the cart, make the adjustments, and immediately submit your changes on the shopping cart page than to hold on to a DataContext, or even the cart itself (if you need to keep the count for display purposes, it is much better to save the count itself in a session variable...you don't need the cart except on your shopping cart page).   The same can be said for user profile information (if you need to worry about elements of a user's profiles, it is better to save those elements than the full profile).  Not carrying around complex objects makes a web application significantly more scalable.

However, when it comes to something like the checkout process, a process that needs to traverse multiple pages (and often both backwards and forwards), the need to manage your DataContext becomes important.  When moving a code base over to LINQ to SQL initially, I tried to use a DataContext per page, and then attempt to detach, attach, pulse until smooth, etc. on the order review page, and it was untenable and unmaintainable. 

Instead, what I found does work is to create a 'Business Process' class (for this example, let's call it Checkout) that manages a single DataContext throughout its entire life cycle.

In its constructor, I would do something like:

public Checkout()

{

_context = new MyDataContext();

}

where _context is a private field that only has a public read-only property.  The checkout class is created at the beginning of the checkout process (typically, when the 'Checkout' button is clicked) and stored in session.

On each page within the checkout process, if I need to do any data access work, I can use the contained DataContext and since it is carried around throughout the process, I can call SubmitChanges() when the order is submitted, and everything works just fine.

I won't walk through the entire process, but imagine a page where you need to enter shipping information.  Your Address object is likely to want to have a State object and at first glance, this poses a problem.  When your UI address form contains a dropdown list to let you choose a state, that list is going to be populated from some other DataContext.  But this is okay.  You can recreate the State object from the value of the selected item by using your contained DataContext, which you will also use to InsertOnSubmit() the new Address object (or if it is an existing item chosen from a user profile generated list, the DataContext will already contain it and so you can SubmitChanges() just fine).  You do have an extra call to the database doing this, but it's pretty minor (frankly, if your scalability is threatened by this, you have other issues), or you could set the StateID directly on your Address object (if that is how your LINQ classes are setup).  You will also need to create a few extra methods in your data layer partial classes to accept a DataContext, but this is again pretty minor.

By focusing your DataContext management on a process instead of at the individual business object level, you can eliminate almost all management entirely (since it is almost always unimportant), implementing a process-level DataContext only where it is needed.

posted on Thursday, February 07, 2008 12:07 AM
Comments
Gravatar
# re: ASP.NET, DataContext, and LINQ to SQL: Business Process Model
jl
2/7/2008 12:40 PM
This sounds a lot like using a "Unit of Work" pattern.
Gravatar
# re: ASP.NET, DataContext, and LINQ to SQL: Business Process Model
Keith J. Farmer
2/7/2008 6:10 PM
"Unit of Work" is exactly how DataContext is supposed to be used, actually.

I would make Checkout disposable, by the way. DataContext is, therefore Checkout should be.

Gravatar
# re: ASP.NET, DataContext, and LINQ to SQL: Business Process Model
jdn
2/8/2008 12:20 AM
Yes, there's certainly nothing decidely new in what I'm doing here. I do think it is helpful within a web application to manage DataContexts this way.
Gravatar
# re: ASP.NET, DataContext, and LINQ to SQL: Business Process Model
Robert
7/21/2008 1:18 AM
I really like your approach, keeping it simple down to the business process in question not only helps with the LINQ DataContext but also allows helps new developers of the system understand which entities are related to a functional area.

Good Work.
Gravatar
# re: ASP.NET, DataContext, and LINQ to SQL: Business Process Model
jdn
7/26/2008 6:38 PM
One thing to keep in mind that I didn't emphasize in the post is that the DataContext is not serializable across web pages if you are using something other than ASP.NET session.

Now, I think you should be using ASP.NET session, and using hardware to ensure that this works across a web farm. I think this is by far the best solution.

But, it is something to be aware of.
Gravatar
# re: ASP.NET, DataContext, and LINQ to SQL: Business Process Model
Viktar
8/14/2008 11:54 AM
Hi,

Generally I don't like to use Session, especially for such big objects as DataContext. It leads to errors that really hard to debug and reproduce (timeouts kind of errors). So far I think attach and detach is the only approach for LINQ to SQL and three tier web application.
Gravatar
# re: ASP.NET, DataContext, and LINQ to SQL: Business Process Model
jdn
8/14/2008 6:28 PM
In this particular case, I don't mind it, and think it is the easiest solution.

Post Comment

Title *
Name *
Email
Url
Comment *  
Please add 2 and 1 and type the answer here: