title: Unit of Work Scope
body: <p>I have a solution that uses webforms for front end &amp; mvc for admin console.</p>
  
  <p>Both UIs consume a service layer via Ninject, and i am having trouble working out a subtle but rather important issue.</p>
  
  <p>Suppose i have a CourseService that returns a list of courses based upon a string search term - the service returns the search results, but i also need to record the search that was made, and how many courses matched that term, for management information purposes.</p>
  
  <p>I started out with the idea that the unit of work would be committed by the UI, at the end of the request, in the page method, such as the button click event.  The same would apply for a controller.</p>
  
  <p>The problem here is that i am relying on the UI developer to call Commit() on the Unit of Work in order for the search to be logged.  The UI developer could happily carry on without calling commit and the results would be returned - but the search would not be logged.  This leads me to the decision of letting the service layer control the scope of the unit of work.  Ninject will automatically pass in the unit of work to both the service layer and the repository implementation, and this will effectively be the same instance as i have told ninject to create it per request scope.</p>
  
  <p>Here is an example of how my layers are written...</p>
  
  <pre><code>public class CourseService
  {
      private readonly ICourseRepository _repo;
  
      public CourseService(ICourseRepository repo)
      {
          _repo = repo;
      }
  
      public IEnumerable&lt;Course&gt; FindCoursesBy(string searchTerm)
      {
          var courses = _repo.FindBy(searchTerm);
          var log = string.format("search for '{1}' returned {0} courses",courses.Count(),searchTerm);
          _repo.LogCourseSearch(log);
          //IMO the service layer should be calling Commit() on IUnitOfWork here...
          return courses;
      }
  }
  
  public class EFCourseRepository : ICourseRepository
  {
      private readonly ObjectContext _context;
  
      public EFCourseRepository(IUnitOfWork unitOfWork)
      {
          _context = (ObjectContext)unitOfWork;
      }
  
      public IEnumerable&lt;Course&gt; FindBy(string text)
      {
          var qry = from c in _context.CreateObjectSet&lt;tblCourse&gt;()
              where c.CourseName.Contains(text)
              select new Course()
              {
                  Id = c.CourseId,
                  Name = c.CourseName
              };
          return qry.AsEnumerable();
      }
  
      public Course Register(string courseName)
      {
          var c = new tblCourse()
          {
              CourseName = courseName;
          };
          _context.AddObject(c);
          //the repository needs to call SaveChanges to get the primary key of the newly created entry in tblCourse...
          var createdCourse = new Course()
          {
              Id = c.CourseId,
              Name = c.CourseName;
          };
          return createdCourse;
      }
  }
  
  public class EFUnitOfWork : ObjectContext, IUnitOfWork
  {
      public EFUnitOfWork(string connectionString) : base(connectionString)
      {}
  
      public void Commit()
      {
          SaveChanges();
      }
  
      public object Context
      {
          get { return this; }
      }
  }
  </code></pre>
  
  <p>In the comments above you can see where i feel that i 'should' be committing my changes, but i feel i may be overlooking a bigger issue by allowing both the service layer AND the repository implementation to control the scope of transactions.  </p>
  
  <p>Further to this - when my repository needs to save a new object, and return it with the newly given primary key intact, this will not happen if i am calling Commit from the UI after the object has been returned.  So the repository does need to manage the unit of work sometimes.</p>
  
  <p>Can you see any immediate issues with my approach?</p>