Question

In a three-layered WPF application, I'm having trouble getting EF to return the most recent data, and I think the issue is related to the way I manage the lifetime of my context. Here is the situation:

A UnitOfWork is made up of many repositories. One service (MyService) also makes use of the UnitOfWork. Additionally, this UnitOfWork must be called directly from the UI without going through a service.

I occasionally make a new window (using ViewModel first) in the ViewModel of my primary window:

var dialog = new DialogViewModel(_eventAggregator, _unitOfWork, Container.Resolve<CarService>());

A UnitOfWork has been inserted into the constructor of this main window ViewModel and is handed to the DialogViewModel.

A UnitOfWork is required by the constructor of CarService and is also inserted there:

public CarService(IUnitOfWork unitOfWork){
    _unitOfWork = unitOfWork;
}

The first time a query to retrieve data and make modifications is made using the CarService in DialogViewModel, everything goes smoothly. The following time the identical query is made to obtain that data, it returns the old/cached version rather than the most recent changed one. This is the query that uses UnitOfWork inside of CarService:

var values = _unitOfWork.GarageRepository.GetSomeValues();
_unitOfWork.GarageRepository.MakeSomeChangesToTheValuesUsingStoredProcedure();

Although values do not have the most recent version of the data when this function is called again, the database has successfully updated it.

I'm using Unity to perform DI, and this is how my container looks:

public class Container
{
     public static UnityContainer Container = new UnityContainer();

     // Called once in the AppBoostraper, as soon as the GUI application starts 
     public void BuildUp()
     {
          Container.RegisterType<IUnitOfWork, UnitOfWork>();
          Container.RegisterType<ICarService, CarService>();
     }
}

How do I correct this issue and why isn't the correct data being returned?

1
12
1/22/2013 1:33:57 AM

Accepted Answer

I eventually identified the issue, which related to how I handled the unitOfWork/dbcontext lifecycle.

At this point, EF was getting the values from the cache rather than the DB since I had loaded some entities, updated them with a stored procedure (making the entities in the code out of current), and then loaded the queries again.

I discovered two solutions for this:

  1. Force the entities to reload using this somewhat "hacky" method:

    Context.Entry(entity).Reload();
    
  2. Use a using to enclose the unitOfWork usage so that the context is disposed at the conclusion of each transaction and new data is obtained the following time. This seems more robust to me and seems more in line with what the UnitOfWork is intended for. Additionally, the UnitOfWork is now injected into the constructors because I wrapped it in a factory.

    using (var uOw = new unitOfWorkFactory.GetNew())
    {
         // make the queries
    }   
    
21
1/22/2013 3:27:40 PM

Popular Answer

Because TransientLifetimeManager is Unity's default lifetime manager, each time it resolves, a new instance is created (including when injected). As a result of your registrations, a new CarService will be created for you, and each time you run Resolve(), a new instance of a UnitOfWork will be injected into your main window ViewModel.

As a result, the CarService receives a different UoW from your ViewModel, and upgrading one will make the other out of date owing to caching.

Setting up a LifetimeManager for the context with the proper scope is required, or you can defer to a factory. Although there aren't many LMs included with Unity, the LifetimeManager class is simply a glorified map (has a Set, Get, and Remove method essentially).

I lack sufficient knowledge about WPF and its lifespan to recommend a solution. It might be a singleton, which means that the context will remain constant during the duration of the program, or it might be supported by the CallContext of a thread.

The UoW instance might be transmitted as an alternative when you call the CarService to resolve it.Container.Resolve<CarService>(new ParameterOverride("unitOfWork", _unitOfWork)) . By doing so, the lifecycle management will remain bound to the lifespan of the ViewModel for the main window. The issue with this strategy is that your VM class knows a little bit too much about the CarService (notably, that it has a UoW in it).



Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow