24
\$\begingroup\$

I am writing a WPF application that needs to access information from a database (I am currently using Entity Framework code first, so data access is via DbContext).

My ViewModels directly instantiate my DbContext derived class and query this to obtain the information they require. I understand that this is bad for the following reasons:

  • My ViewModel now has a dependency on DbContext.
  • my viewModel is more difficult to test.
  • It will be difficult to switch to a different data provider if required e.g. ObjectContext instead of DbContext.

The common solution I have seen to this problem is to define a repository to keep my ViewModels unaware of which data access technology I am using.

I have defined the following generic repository class:

public interface IRepository<T>
{
    IEnumerable<T> GetAll();
    IEnumerable<T> Find(Expression<Func<T, bool>> where);

    // other data access methods could also be included.

    void Add(T entity);
    void Attach(T entity);
    void Delete(T entity);
}

My concrete repository looks like this:

public class Repository<T> : IRepository<T> where T : class
{
    private DbSet<T> _entitySet;

    public Repository(DbContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        _entitySet = context.Set<T>();
    }

    public IEnumerable<T> GetAll()
    {
        return _entitySet;
    }

    public IEnumerable<T> Find(Expression<Func<T, bool>> where)
    {
        return _entitySet.Where(where);
    }

    public void Add(T entity)
    {
        _entitySet.Add(entity);
    }

    public void Attach(T entity)
    {
        _entitySet.Attach(entity);
    }

    public void Delete(T entity)
    {
        _entitySet.Remove(entity);
    }
}

Any viewModel that requires access to the database now has a constructor parameter so that a repository can be injected. As far as I can tell this solves all of the problems listed above - my viewModels no longer depend on 'DbContext', they can be tested by using a mocked implementation of the IRepository interface and I could switch to the ObjectContext API by creating a different implementation of the IRepository interface.

This is great except in some cases I may require access to other repositories that contain different entities E.G. Customers and Products. I may also sometimes need to add, update and save the changes to multiple entities in one go. I could change my viewModel constructors to accept just the entities they require but this doesn't smell right to me.

One solution is to use the following interface:

public interface IUnitOfWork : IDisposable
{
    IRepository<T> RepositoryFor<T>() where T : class;
    void SaveChanges();
}

The idea here is that the unit of work allows my viewModels to request entities from the data source and any changes can be saved in one go. The implication of this interface is that any entities requested belong to the same 'context'.

an example of a concrete implementation looks like this:

public class UnitOfWork : IUnitOfWork
{
    private DbContext _context;

    public UnitOfWork(DbContext context)
    {
        if (context == null)
            throw new ArgumentNullException("context");

        _context = context;
    }

    public IRepository<T> RepositoryFor<T>() where T : class
    {
        return new Repository<T>(_context);
    }

    public void SaveChanges()
    {
        _context.SaveChanges();
    }

    public void Dispose()
    {
        _context.Dispose();
    }
}

My ViewModel constructors now have an IUnitOfWork injected rather than a repository and the IUnitOfWork instance allows me to request generic repositories for each entity and then save all changes to the same context using the SaveChanges() method.

This still solves the problems listed earlier and also allows me to make changes to multiple entities within my viewModels. My next concern was over the lifetime of the IUnitOfWork instance. My implementation is using DbContext and my understanding is that the this type should be (generally speaking) short lived.

Consider the following scenario:

  1. An IUnitOfWork instance is passed into my ViewModel constructor.
  2. I retrieve some entities, work with them and then save the changes to the database.
  3. I dispose the IUnitOfWork instance.
  4. I now need to carry out another series of operations so need to create a new IUnitOfWork instance - My ViewModel is now dependant on my concrete application of the interface.

The alternative is to keep the IUnitOfWork around for the lifetime of the ViewModel but this means that the underlying DbContext will be keeping track of all changes I make.

My solution to this was to create another interface:

public interface IUnitOfWorkProvider
{
    IUnitOfWork GetUnitOfWork();
}

The idea here is that a concrete instance will be injected into my ViewModels via the constructor. Whenever I need to do any data access I will just do something like this:

using (IUnitOfWork uow = provider.GetUnitOfWork())
{
    // Carry out all data access here...
    uow.SaveChanges();
}

What I would like to know is, is my implementation of the repository and unit of work patterns acceptable? Will this cause me any major problems?

Update

As was pointed out to me by dreza in the comments, my viewModels are retrieving their own data from the repository. I'm not sure how to pass the data into my viewModels without having a unique interface or class per viewModel to encapsulate this information.

In it's current state the repository can also (potentially) return any entity repository that is requested. e.g. in my customerViewModel I may want to work only with Customer and Product entities but there is nothing to stop me requesting other unrelated entities.

\$\endgroup\$
2
  • \$\begingroup\$ The implementations seem pretty standard to me. However I'm not sure of the usage of these within viewmodels. I always tended to go down the track that other objects were reponsible for populating the viewmodels themselves, not the viewmodels fetching the needed data. Is there any particular reason for this approach? \$\endgroup\$
    – dreza
    Aug 2, 2012 at 1:15
  • \$\begingroup\$ This is simply what I have come up with myself based on the information I have recently learnt. I am certainly open to learning a different approach though; do you have any examples of how your method would be achieved? All the MVVM examples I have seen are usually fairly simple and just create the data directly. \$\endgroup\$
    – Benjamin
    Aug 2, 2012 at 7:12

1 Answer 1

2
\$\begingroup\$

NOTE: After Ben correctly commented that he was doing this from the WPF not MVC approach my answer was biased to MVC so although I'll leave it here it it may not have much relevance to what he is actually looking for.


Typically I worked on the assumption that as much as possible my viewModels were DTO's perhaps with validation attribute capabilities, or I've seen some uses where they use message notification to provide updates to the view. I guess the theory is that the view models themselves could be populated by a variety of methods, or the data used to populate them could come from a variety of places.

From what I gather a view model is essentially a method of of providing a set of data that is required by the specially by the caller/view in question. This data may come from a variety of places, and these places may vary. The viewmodel itself doesn't care, it just transports the data to the view that knows what to do with it.

Also, in my mind by doing this I think unit tests may be easier to write. There are many ways of skinning the cat of course. My favourite flavor of the month is using a service like class to do any mapping from data model to view model. I've also heard modules such as Auto mapper are excellent modules for doing this mapping for you as well.

NOTE: These are just examples of how you might use your Repository and IOW without making them part of your viewmodel.

So in my current way of working, I do something like below:

public class TopLevelClass
{
    private readonly IUnitOfWork _unitOfWork;

    public TopLevelClass(IUnitOfWork iow)
    {
       // injected by a DI framework such as Ninject, Unity ??
       _unitOfWork = iow;
    }

    // just an example of doing something with not using IUnitOfWork in viewmodel
    public void DoMySpecialSomething(string mySpecialId)
    {
       var repository = _unitOfWork.RepositoryFor<MySpecialModel>();
       var mySpecialModel = repository.SingleOrDefault(p => p.Id = mySpecialId);

       var viewModel = new MySpecialService().GetViewModel(mySpecialModel);

       // do something with my view model ???
    }

    public MySpecialViewModel GetSomethingEvenMoreSpecial(string mySpecialName, string goldMedal)
    {
       var mySpecialModel = new MySpecialModel
                               {
                                  Name = mySpecialName,
                                  OlympicMedal = goldMedal
                               };

       return new MySpecialService().GetViewModel(mySpecialModel);
    }
}

// Maybe this might also work from an IMySpecialService interfaces ????
public class MySpecialService
{
    public MySpecialViewModel GetViewModel(MySpecialModel model)
    {
       return new MySpecialViewModel
                {
                   Id = model.Id,
                   IsEnabled = !string.isNullOrEmpty(model.Name),
                   Name = model.Name,
                   OlympicMedal = model.Medal
                };
    }
}

public class MySpecialViewModel
{
    [DisplayName("Your Id")]
    public int Id { get; set; }
    // other properties etc
}

public class MySpecialModel
{
   public int Id { get; set; }
   // other properties here
}

I guess if I was doing TDD I would have created the view model and stubbed the MySpecialService first and created perhaps a test like

// Using standard microsoft testing project
[TestMethod]
public void MySpecialModel_IsValidTest()
{
   var model = new MySpecialModel
                 {
                    Id = 45
                 };

   var service = new MySpecialService();
   var viewModel = service.GetViewModel(model);

   Assert.AreEqual(model.Id, 45);
}  

I hope that might give you some ideas in what you might want to (or not) do differently.
\$\endgroup\$
3
  • \$\begingroup\$ Thanks you for your feedback. Just to be clear, when I talk about viewModels I am talking about them being used in the context of WPF and not ASP.NET MVC. Its not entirely clear from your response so I thought it was worth mentioning just to be clear. \$\endgroup\$
    – Benjamin
    Aug 3, 2012 at 12:02
  • \$\begingroup\$ @Benjamin ahh ok, my bad. You did say that in your question. sorry about that, you can probably ignore my answer unless it gave you some new ideas :) \$\endgroup\$
    – dreza
    Aug 3, 2012 at 20:35
  • \$\begingroup\$ no problem at all. +1 anyway as your point about viewModels not querying the data source directly (either directly via DbContext or via an interface) is still valid and has made me reconsider my approach. \$\endgroup\$
    – Benjamin
    Aug 4, 2012 at 14:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.