Unit of work scoping in LightSpeed
Tagged as LightSpeedA common pattern for working with persistent storage is the Repository pattern. This typically takes the form of a class which encapsulates all of the data access code, usually instantiated as a member of a common base Page or (for MVC/MVP architectures) Controller or Presenter class. In LightSpeed terms, the unit of work is hidden behind the Repository facade, so that your application code deals only with the domain objects.
A consequence of this is that if the unit of work is hidden away in the repository class, so is the unit of work lifecycle and sharing logic. Your application can’t control the lifecycle as it would do if it constructed the unit of work directly.
But we couldn’t build a particular lifecycle into the base LightSpeed repository class: different environments need different lifecycle and sharing logic. For example, in a Web application, you want each request to get its own unit of work. You don’t want units of work hanging around from one request to the next, and you don’t want simultaneous requests sharing the same unit of work. In a Windows Forms application, you would need a different and potentially application-dependent strategy. So it’s necessary instead to encapsulate this lifecycle and sharing logic in a strategy class. Then the application can just delegate selecting the correct unit of work to the strategy class, and stop worrying about lifecycle concerns.
In LightSpeed, these lifecycle and sharing strategy classes are called unit of work scope classes. We provide two of them out of the box, a unit-of-work-per-request strategy for Web applications, and a unit-of-work-per-thread strategy for batch tools.
Scope classes inherit from UnitOfWorkScopeBase, an abstract class which basically defines just one interesting property, Current. The Current property represents the unit of work that should be used in the current situation. A concrete scope class will override Current to provide creation and partitioning logic appropriate to the particular strategy.
Let’s look at a common example. As noted, a Web application wants a unit of work per request. That is, we want to be able to write page, controller or presenter code that looks like this:
var products = this.Repository.GetAllProducts(); MakeSomeChanges(); this.Repository.SaveChanges();
and know that within any given request all our entities will be part of the same unit of work (so that associations will be wired up correctly, etc.), and that SaveChanges will be applied to that same unit of work; but also that different requests will get different unit of work instances, so that the SaveChanges() call won’t save changes currently under way in other requests
How can we encapsulate this in a scope class? The answer is to implement Current something like this:
TUnitOfWork current = (TUnitOfWork)HttpContext.Current.Items["UOW"]; if (current == null) { current = LightSpeedContext.CreateUnitOfWork(); HttpContext.Current.Items["UOW"] = current; } return current;
The strategy checks to see if there is already a unit of work associated with the current request. If so, it returns that existing unit of work. If not, it creates a new one and associates it with the current request, so that subsequent calls to Current as part of the same request will return the same unit of work.
Then the repository will internally have an instance of this scope class, and use its Current unit of work to handle requests:
public class StoreRepository : RepositoryBase<StoreUnitOfWork> { public StoreRepository(string configName) : base(new PerRequestUnitOfWorkScope<StoreUnitOfWork>( new LightSpeedContext<StoreUnitOfWork>(configName))) { } public IList<Product> GetAllProducts() { return UnitOfWorkScope.Current.Products.ToList(); } }
So not only is the application code uncluttered by details of the persistence mechanism and the unit of work, the repository methods are free of lifecycle and partitioning details as well. All of that stuff is hidden neatly away in the scope class. In particular this facilitates testing because the HttpContext-dependent scope class can be swapped out for a simple scope class (see http://www.mindscape.co.nz/blog/index.php/2008/05/12/using-the-unit-of-work-per-request-pattern-in-aspnet-mvc/ for more info.
And that’s all there is to scope classes. A lot of customers find them a bit confusing but really you only need to know two things: first, they’re just simple wrappers that do a little housekeeping and a little encapsulation, and second, you only need them if you’re using the repository pattern, or if you want to save writing the HttpContext wrapper code yourself. Many LightSpeed applications will never need a scope class at all.
4 Responses to “Unit of work scoping in LightSpeed”
Leave a Reply
Categories
BrainDump (1)
Community Code (4)
Events (16)
F# (14)
General (53)
Lab Samples (2)
LightSpeed (268)
MegaPack (8)
News (71)
NHibernate Designer (26)
Nightly news (53)
Phone Elements (24)
Products (87)
Projects (5)
Screencast (6)
SharePoint (3)
Silverlight (14)
Silverlight Elements (66)
SimpleDB Management Tools (20)
Visual Studio (9)
VS File Explorer (7)
Web Workbench (39)
WPF (44)
WPF Diagrams (57)
WPF Elements (110)
WPF Property Grid (32)



Posted by Ivan Towlson on 19 May 2009 



well, indeed, repository pattern is the _main_ pattern when doing domain driven design and I would encourage everyone to follow it (unless there is some big reason not to).
More to it that Lightspeed is more suited to work nicely with this pattern that e.g. Linq to SQL “was”.
I wish Lightspeed would name its UOW class as “session” (because that’s what it is) like its competitors and provide us with a finished uow (or two) which you in Mindscape call uow-scope.
At least one O/R mapper is following named pattern and although is utterly complicated I think there wasn’t need to change what worked nicely (session factory will provide you with session which you will wrap in unit of work, nicely written on nhforge).
if I am of course not missing something…(but my thumb is up for the @renaming@ in LS 3.0)
and I almost forgot, great article Ivan
Hello Ivan,
How do you propose managing the context for windows apps?
With L2S, we were reusing the same biz stack (model, data services w/ repo pattern, model services, etc…) for a windows app, service, and web app.
Problem was in the win app. Without caching, each repository would new up a L2S Context(same as LS UOW basically) and operations in a TransactionScope would be elevated to the DTC, which we definitely did not want. Thread scoping wouldn’t work because you definitely get stale data issues in the life of a windows app.
I ended up producing a “DataContextProvider” very similar to your UOW scoping. I have a strategy pattern scope for web (httpcontext) and one for service/batch (threadcontext). But we also needed something to help us scoping in the win app. I ended up producing an additional “nocache” provider and a new construct called DataContextScope. This scope could be used in place of a TransactionScope with a using block such as:
using(var x = new DataContextScope())
{
Data Operation 1;
Data Operation 2;
}
This scope guarantees that the app is using one datacontext (ie UOW) inside of the using statement across repositories. In this way, the transactions weren’t elevated to DTC and the biz stack could be used by each app, no matter what caching strategy was used. It works well, but seems like a complicated approach.
Did you guys think about what to do in the case of windows applications? Especially a windows app that may use the same biz stack as a web app? Just wondering if you guys had come up with a good approach or if you’d considered this issue.
Thanks,
Eric
Hello Eric,
Just to let you know, JD has promised to write up some advice based on a rich client project he’s currently working on, but he’s a bit snowed under at the moment, so he’s not had the chance to get round to it yet. Soon we hope!
Hi Eric,
Just to clarify so that I’m on the same page as you – you’re basically establishing a singleton UoW Scope in your application to ensure you keep tight control on it?
Generally one of the things that works well with web applications is that you’re working with imposed restrictions of the web – statelessness, clearly defined edges etc. With Windows applications you’re able to do whatever you want – no matter how wise it may or may not be! :-)
Generally speaking, the best bet is to apply a design pattern such as MVC/MVP/MVVM as this starts to define boundaries to actions which you can then more nicely scope. This helps reduce the issue of every control and window randomly querying data constantly.
In our own previous applications we have taken the approach of holding a unit of work behind a base controller (and even then usually inside a repository) and only allowing the parent class to call against it. This starts solving the messy management of the unit of work that can appear in some desktop applications.
We have in the past simply re-queried the database if we need to ensure that data is not stale to the user however more often than not you would find this isn’t a requirement in most applications – this is the approach most applications take. You hold a view and you may have a refresh button but it’s otherwise just the data at last check.
Of these two issues (and I know there are others) which is causing the most pain with your application? Stale data or simply managing the UoW in a nice manner?
We’re planning to ship a good sample around winforms / wpf applications based on LightSpeed with LightSpeed 3.0 as we know there is a real need for improved guidance around this.
If you wouldn’t mind, ping me at jd@mindscape.co.nz and we can discuss this with a bit more room for code examples via email. The more I can understand of your situation the better I can help.
I hope that helps.