Mindscape LightSpeed - User Reference & API Documentation
Unit of Work Mechanics

As discussed in Architecture & Patterns, LightSpeed uses the Unit of Work pattern as a way of organizing logical sets of database operations.

A unit of work in LightSpeed is primarily two things:

  1. A database connection
  2. An Identity Map of references to the entities currently in memory.

The Current Unit of Work & Scopes

As previously described, LightSpeed transparently manages the internal unit of work mechanics behind the static Repository facade. A key aspect of this implementation is the notion of a current unit of work for a given scope. A scope is just a context within which there is a single, isolated unit of work present (a unit of work is inherently not thread-safe as it encapsulates a database connection) – i.e. the current unit of work. LightSpeed supports two scoping strategies and automatically selects the strategy appropriate for your application:

  1. Thread Scope – There is a unit of work per thread.
  2. Web Request Scope – There is a unit of work per web request.

The first time a Repository method is called, LightSpeed will automatically create a new unit of work for the current scope. As entities are loaded through Repository.Find or new entities are added through Repository.Add they become tracked by the current unit of work. If any of the entities are modified they will be automatically persisted during the next save operation. There are two ways trigger a save operation:

  1. Call Repository.CompleteUnitOfWork. The typical approach. Flushes pending changes to the database and disposes the current unit of work, thereby freeing associated resources.
  2. Call Repository.SaveChanges. Flushes pending changes to the database but does not complete the current unit of work.

A LightSpeed unit of work is designed to be short-lived.
 

SaveChanges vs. CompleteUnitOfWork

Repository.SaveChanges persists any new, modified or deleted entities to the database. It allows you to incrementally persist a set of changes without completing the current unit of work. This is useful in certain scenarios such as unit testing. Normally, you can just call Repository.CompleteUnitOfWork which internally calls Repository.SaveChanges before it disposes of the underlying resources (database connection, identity map etc.)

Passing false to Repository.SaveChanges causes LightSpeed to clear the internal Identity Map. This is useful when you want to guarantee that any subsequent entity Find operations return a new entity instance.
 

Attaching Entities to a new Unit of Work

Sometimes an application will need to hold a reference to an entity after the unit of work associated with the entity has been completed. For example, maybe the entity has been held in ASP.NET Session state. To support this scenario, LightSpeed provides the Repository.Attach method. This method allows you associate an entity with a new unit of work. The entity then becomes tracked like any other entity associated with that unit of work.

Nested Units of Work

Occasionally it is useful to be able to have multiple units of work alive within the same scope. LightSpeed supports this through the concept of a nested unit of work. To create a nested unit of work simply call the Repository.BeginUnitOfWork method. This method effectively pushes a new unit of work on to an internal unit of work stack making it the new current unit of work. Calling Repository.CompleteUnitOfWork will dispose the nested unit of work and pop it from the stack causing the previous unit of work (if any) to become current.