Syndicate

News

My name's Marco De Sanctis and I'm an IT professional from Italy. This is my technical blog, about .NET and related application development and design technologies.

Download my Resume (.doc)

Recent Comments

10/23/2008 at 3:48 PM

sorry, my previous post was not complete... I trie...
by glondi

Read more...

9/22/2008 at 10:03 AM

Good one!!!Could you please post source code for t...
by Nisa

Read more...

9/10/2008 at 5:53 PM

I didn't even realize people were aware of the WPF...
by Mike Brown

Read more...

9/8/2008 at 1:22 AM

Marco,How are you handling scenarios where you nee...
by ctodd

Read more...

9/3/2008 at 1:00 AM

@ctodd: Hi,basically for the reasons I described a...
by Marco De Sanctis

Read more...

Recent Posts

Crunch mode is a pure waste of time, energy and money

7/31/2008 at 5:41 PM

Read more...

Double Click on the .sln file doesn't open Visual Studio on Vista

7/27/2008 at 9:02 AM

Read more...

Domain Model & Aggregates: when do master-detail associations happen?

7/22/2008 at 4:08 PM

Read more...

How I Got Started in Software Development

7/14/2008 at 12:16 AM

Read more...

Unleash the power of VisualStateManager with custom states

6/30/2008 at 12:12 AM

Read more...

Linq To Sql in real word Web applications

posted on Tuesday, May 20, 2008 11:34 PM | Filed Under [ LINQ ASP.NET ]

As my Italian friends probably know, I'm a huge NHibernate fan, as I decided to permanently adopt it in many desktop and web apps I've built or designed during the last 2-3 years; dealing with Session life cycle management in ASP.NET apps is pretty simple if you use well known patterns like

  • Session per Request
  • more rarely, Session per Conversation

In other words, you have a session alive and kickin' for the whole business transaction your WebForm is accomplishing and, being the NHibernate Session a Unit of Work implementation, this is absolutely faithful to that pattern definition.

For some reasons, using a similar approach with Linq To Sql's DataContext is not as easy. Let's take a look.

Dealing with detached objects

Let's start saying that associations in L2S are lazy fetched by default, so you need to have a context alive while navigating the entity graph if you don't want ObjectDisposedExceptions to be raised:

image

When adopting a Session per Request pattern, you must frequently detach/reattach the entity versus the current request's DataContext; however, attaching a detached entity in Linq To Sql is not as easy as it's supposed to be, as it isn't a supported scenario. I blogged in Italian a while ago about some strange reattaching behaviors I experienced in Beta2; RTM throws an exception if you try to reattach a persistent entity with associations not yet initialized, at least that's a more consistent behavior, although it doesn't help.

image

In other words, unless you don't want to deal with workarounds, you can't use Session per Request pattern with Linq To Sql.

Moving towards Session DataContext per Conversation

That brings us to the decision of having the same DataContext alive for the whole business transaction. I'm fine with that, although the architecture becomes a bit more complicated because its life should span several postbacks. After chatting a while with my friend Alk, I realized that ASP.NET's Cache is an awesome storage mechanism for DataContexts because:

  • In a perfect world, every business transaction should be explicitely closed. In real world, however, users tend to close their browsers without notice. If we use sliding expiration, the ASP.NET's caching infrastructure takes care itself on getting rid of every pending DataContext that hasn't properly been disposed.
  • Cache's sliding expiration is automatically renewed on every access.
  • Cache provides a callback mechanism, so we can execute custom code when a DataContext has expired.
  • We can configure Cache to not remove DataContexts when the system is in need of memory.

Instead of directly storing the DataContext, it's a better choice to wrap it in a generic UnitOfWork instance; this allows us to inject a bit of additional (and useful) logic:

The Items property, for example, is a string/object dictionary (an idea borrowed from NHibernate.Burrow) used to store custom transaction items that need to last till the transaction ends; I've also provided a Disposing event if the user wants to execute some custom code when a UnitOfWork is closed.

A UnitOfWorkContainer singleton object keeps track of all active UnitOfWorks and provides methods to start, rollback or commit (business) transactions:

image

Thanks to that, building a new UnitOfWork and storing it in the cache repository is only a matter of calling the BeginTransaction<T> (T is the Linq to Sql context's concrete type) of the UnitOfWorkContainer singleton class:

image

That method returns an ID which can be easily stored (f.e. using Viewstate) and will be used to retrieve the current UoW during the future postbacks. Now that a UoW has been created and stored into the container, we can retrieve it very easily

image

and we can use it to interact with the underlying Linq DataContext or with the Items storage as well; for example, the Page_Load method in my example contains the following code:

image

Thanks to this code, in every postback we have a reference to the person currently edited through the entity filed, we can freely navigate its object graph with the DataContext automatically querying the underlying database if it needs to lazily initialize any property, and tracking every change we make to any entity, being it the current Person instance or any associated one. Not bad, isn't it?

After some postbacks, here it comes the end of the conversation, in which the user is asked to say "Ok" and persist the changes, or say "No" and cancel everything; this ends the business transaction and invalidates the UnitOfWork:

image

Few details on what happens behind the curtain

The UnitOfWorkContainer class acts as a repository, providing methods to manage a UoW's lifetime and retrieve it given its Id. Once the user decides to begin a new business transaction, a new UoW is created and added to ASP.NET Cache:

image

Two details to notice here:

  1. The cache item is marked as NotRemovable, so it won't be cleared in case of memory shortage; it will disappear only after a 10 minutes sliding timeout or if explicitely removed.
  2. I've subscribed a CacheItemRemovedCallback to dispose the UoW once it has been removed from the cache (and, therefore, not reachable anymore from the client code)

Obviously this is only a very simple example, something very similar to what I used to do with NHibernate. For those who are interested on it as a starting point for their own apps, source code is available here.

kick it on DotNetKicks.com

Comments

Gravatar
# re: Linq To Sql in real word Web applications
Posted by Egil on 5/21/2008 11:40 PM
I like this.

A few comments though:

I have always had the impression that the DataContext was suppose to be as short lived as possible. This pattern sort of goes against that.

Also, traversing the object graph is freely seems like a wast of resources - a lot of round trips to the SQL server. I think the recommended method is to use LoadWith method. I guess it is a balancing act between convenience and performance.

Another thing that hit me. If two users is working with the same set of data, there will surly be two active DataContexts alive, but are the DataContexts intelligent enough to share the data object between them, or will there be duplicated items all over?

I am about to start building a internal web application in my company, and I am tempted to forgo all the glory of object tracking and just use Linq to SQL just to retrieve data.

Thanks for an inspiring post, hope my comment are not to negative, it is basically a recap of the debate I have been having with my self lately.

Regards, Egil.
Gravatar
# re: Linq To Sql in real word Web applications
Posted by Maarten on 5/22/2008 8:49 AM
I've tried pretty much the exact same thing, and I could get it to work with a new DataContext on the PostBack. I also used the Attach-method, but used the overload where I also give the original object as an argument. I saved the original object (and the changing one btw) in the ViewState of the page.

I don't have the code here :-(

Cheers,
Maarten
Gravatar
# re: Linq To Sql in real word Web applications
Posted by Marco De Sanctis on 5/22/2008 12:48 PM
@Egil
Your feedback lead me to that post
http://www.codemetropolis.com/archive/2008/05/22/when-lazy-loading-associations-is-useful.aspx
about when lazy loading is useful.

However, having a DataContext alive is essential if you're using its object tracking feature. If you're not (as you wrote :D) and you're sure you're not going to need any additional fetch, you can deal with its lack.
However, consider that having a DataContext alive for the shortest time possible isn't such a big deal in terms of optimization: it simply disposes the internal connection, which is automatically closed after every db access.

@Maarten
Attaching a not completely initialized entity (i.e. with relationships to other entities not yet loaded) isn't a supported scenario and doesn't work in L2S AFAIK.
Gravatar
# re: Linq To Sql in real word Web applications
Posted by Egil on 5/22/2008 3:42 PM
@Marco

Thanks for the feedback.

How would the caching strategy be when using the Unite of Work model? If each user requests pretty much the same subset of date, would that have to be retrieved from the SQL server once per UnitOfWork, or is there a way to cache the data such that it can be reused by each UnitOfWork and only exists once in memory?

Gravatar
# re: Linq To Sql in real word Web applications
Posted by Marco De Sanctis on 5/23/2008 2:01 AM
Hi Egil, sorry for replying so late but I really didn't have time.

Well, integrating ASP.NET cache with Linq To Sql is a bit tricky, because the ORM doesn't provide some kinda of an infrastructure to do it (as, f.e. NHibernate does in an excellent way).

However, a simple example could be about many-to-one associations, leveraging the identity map.

Let's suppose you have a Player entity with a Role property (of type Role): Point Guard, Small Forward, and so on... Roles can be considerent invariant throughout the whole application life, so thery're good candidates to be cached.

What you can do in a PlayerList form, is retrieving all the Roles from the cache and Attaching them to the current UnitOfWork.DataContext. You can do it as they are completely initialized.

Fair enough. Now, when accessing every player's Role property, L2S won't fetch it from the DB: that Role is for sure already stored into the internal Table<Role> and the identity map will use that instance when lazy loading and no query will be executed.
Gravatar
# re: Linq To Sql in real word Web applications
Posted by Egil on 5/23/2008 10:54 AM
No problem Marco, interesting idea though.

I have been playing around with a few ideas on how to make the UOW pattern fit in to a classic layered application, i.e. a facade that the webforms talk to, a business layer below that, and again a data access layer below that.

It seems to me that the UOW would have to be on the BLL, and have the facade expose methods for manipulating the UOW's.

Alternatively, the UOW should be on top of the facade and wrap that instead of a DataContext, since the UOW pattern really only seems relevant in web scenario.

I would love your thought on this.

ps. please consider making the comment box bigger, seven small lines makes it hard to for a general view of ones post.
Gravatar
# re: Linq To Sql in real word Web applications
Posted by Marco De Sanctis on 5/23/2008 4:17 PM
Well,

I see better a solution in which a Facade wraps the UoW and integrates f.e. the cache functionalities: as you correctly say, it belongs to the BL and shouldn't be aware of any ASP.NET related infrastructure.

Actually I don't completely agree with you about the UoW being relevant only on a web scenario; the concepts I wrote in this post IMHO perfectly fit in a smart client environment too, although you don't need all the infrastructure to store it: UoW is something able to track objects status within a business transaction, and that is exactly what a DataContext does. Maybe you don't need to encapsulate it in a UnitOfWork wrapper, but you still need something capable to track object changes and an identity map to sync object identity and database identity, especially if you're going to need a business transaction that spans over more than one single form.

BTW, thank you for the tip about the comment box: i'll fix it ASAP, I actually had to write this comment on notepad!! :-)

Bye,
Marco
Gravatar
# re: Linq To Sql in real word Web applications
Posted by Egil on 5/23/2008 4:45 PM
Ahh ok. So if the Facade wraps the UoW, the Facade would basically take over the responsibility UnitOfWorkContainer class.

The Facade would however have to be aware of the ASP.NET infrastructure for this to work, but I guess that is acceptable.
Gravatar
# re: Linq To Sql in real word Web applications
Posted by Daniel on 5/29/2008 7:58 PM
This is an interesting idea. For the applications I've created with L2S, I stuck with a DataContext scoped to the HttpRequest, and played back changes on that with a delegate so that I can just use lambdas on the client to manipulate entity objects: http://www.dimebrain.com/2007/12/using-linq-to-s.html
Gravatar
# re: Linq To Sql in real word Web applications
Posted by ctodd on 9/2/2008 9:36 PM
I'm not an expert on this by any means; however, I am curious as to why you chose cache over session? Is there some benefit that I am not aware of? It seems to me that if you used a session, you wouldn't need a guid to keep each user's UOW separate.

By the way, great work! I am playing with it now. The only concern I have is the effect of orphaned UOWs. I know the cache will expire, but it still freaks me out.

Chris.
Gravatar
# re: Linq To Sql in real word Web applications
Posted by Marco De Sanctis on 9/3/2008 1:00 AM
@ctodd: Hi,
basically for the reasons I described above; obviously you can use sessions as well, however you would be forced to set a expiration time for *the whole* session object.

With ASP.NET's cache I can set a particular time out for the UoW, while keeping different timeout values for other objects that have nothing to do with session per conversation pattern (like the data needed to feed your site's home page).

Bye and thanks for reading it.

M.
Gravatar
# re: Linq To Sql in real word Web applications
Posted by ctodd on 9/8/2008 1:22 AM
Marco,

How are you handling scenarios where you need access to inserted entities before you submit changes? My problem is, I am using a 3P control (ASPxGridView) and I am unable to see inserted entities until I submit changes. I know why it is happening, I just don’t know how to get around it. I appreciate any help you can provide.

Thanks,
Chris.
Gravatar
# re: GridView DataBinding problem
Posted by glondi on 10/23/2008 3:48 PM

sorry, my previous post was not complete...

I tried extending your code in order to let the user add/modify/delete Addresses collection without any restictions and save the final list at later time.

The problem was that GridView control was not able to properly bind to EntitySet<Address> object. It was impossible to read user supplied values (grid edit mode) in gridAddresses_RowUpdating event.

Do you have any ideas of what was causing aforementioned problem?

Greetings,
glondi

Gravatar
# tpialxqo
Posted by tpialxqo on 10/31/2008 6:48 AM
tpialxqo
Gravatar
# Animal sex cartoons.
Posted by Animal sex movies. on 1/22/2009 1:24 AM
Animal sex zoo. Free animal sex. Animal sex with human. Animal sex. Farm animal sex.
Gravatar
# Try viagra for free.
Posted by Viagra. on 3/17/2009 8:19 AM
Viagra. Buy viagra online. Viagra online. Female viagra. Is viagra soft tabs better. India viagra.
Gravatar
# Viagra england.
Posted by Viagra on line. on 3/18/2009 7:48 AM
Viagra. Viagra online. Generic viagra.
Gravatar
# Generic cialis.
Posted by Cialis. on 3/19/2009 5:35 AM
Buy cialis online. Cheapest cialis. Cialis attorneys. Liquid cialis. Cialis.
Gravatar
# Online phentermine.
Posted by Phentermine. on 3/19/2009 9:04 AM
Buy phentermine cod. Phentermine. Diet tablets phentermine. Order phentermine online. Phentermine diet pill.
Gravatar
# Buy levitra paypal.
Posted by Online pharmacy cost levitra. on 3/23/2009 2:37 AM
Levitra gamecube online games. Online pharmacy cost levitra. Levitra online. Buy levitra cheap levitra online get back to life. Levitra.
Gravatar
# Levitra.
Posted by Buy levitra online. on 3/23/2009 9:38 AM
Levitra erectile dysfunction treatment. Zoloft levitra pe cure. Levitra attorneys. Levitra. Long condition how last levitra does. Discount levitra.
Gravatar
# Herbal phentermine.
Posted by Buy phentermine. on 3/24/2009 5:04 AM
Phentermine. Lowest price for phentermine. Buying phentermine.
Gravatar
# retrieved signed fourth warm
Posted by retrieved signed fourth warm on 4/26/2009 8:16 PM
ipcc clathrate pattern review volcanic movit 1979
Gravatar
# Xanax bars.
Posted by Generic xanax. on 7/8/2009 8:23 AM
Xanax bars. Xanax.
Gravatar
# Ephedra.
Posted by Ephedra weight loss products. on 7/9/2009 10:49 PM
Chat on ephedra. Ephedra products. Fda approved ephedra for. Ephedra 30mg. Ephedra yellow swarm. Ripped fuel without ephedra. Delaware ephedra lawyers. Ephedra.
Gravatar
# Buy viagra.
Posted by Viagra. on 7/11/2009 12:17 AM
Cheap viagra. Viagra on line. Viagra lawyers. Viagra price.
Gravatar
# Vicodin.
Posted by Vicodin. on 7/12/2009 12:12 AM
What does vicodin look like. Vicodin without prescription. Cheap vicodin cod. Effects of vicodin. Buy vicodin.
Gravatar
# Xanax.
Posted by Xanax withdrawal. on 7/13/2009 12:32 AM
Xanax. No prescription xanax.
Gravatar
# Xanax.
Posted by Buy 180 xanax 2mg. on 7/14/2009 12:42 AM
2mg xanax order. Xanax no prescription. Buy 180 xanax. Xanax. Generic xanax 2 mg no prescription. Buying xanax with mastercard. Xanax lawsuits.
Gravatar
# Tramadol 93.
Posted by Tramadol. on 7/15/2009 12:44 AM
Tramadol sr 100.
Gravatar
# Viagra.
Posted by Viagra patent. on 7/18/2009 11:29 PM
Female viagra.
Gravatar
# Percocet.
Posted by Percocet dosages. on 7/19/2009 12:51 AM
Percocet sexual effects. Percocet addiction. Percocet. How to extract acitaminiaphine from percocet. How to extract acetaminophen from percocet. Percocet picture.
Gravatar
# Percocet withdrawal symptoms.
Posted by Percocet. on 7/22/2009 12:38 AM
Buy percocet online no prescription. Percocet aspirin. Generic percocet. Bioavailability of percocet.
Gravatar
# store recent least
Posted by store recent least on 10/15/2009 9:41 PM
estimated kyoto list majority instrumental change sectors clathrate
Gravatar
# content gas
Posted by content gas on 10/25/2009 10:45 AM
allowing weather benefits part
Gravatar
# half feedback natural down
Posted by half feedback natural down on 11/2/2009 12:15 AM
decreases users turn population stabilization routes stories available
Comments have been closed on this topic.