views:

110

answers:

3

I'm a bit confused about when using the "IRepository pattern", when actually to load the data.

Currently I have something like this:

public class MainViewModel : ViewModelBase
{
    // EF4 generated ObjectContext 
    private ScorBotEntities context = new ScorBotEntities();         

    // Custom IUserRepository class
    private IUserRepository userRepository;

    public MainViewModel()
    {
        this.userRepository = new UserRepository(context.Users);
    }

    public ObservableCollection<User> Users
    {
        get
        {
            return new ObservableCollection<User>(userRepository.GetAll());
        }
    }
}

ScorBotEntities are autogenerated using EF4 (I had a look at POCOs, to much work for this sized project).

You can find the definition of the UserRepository here: http://code.google.com/p/i4prj4-g2/source/browse/ScorBotRobotics/ScorBotRobotics/Repositories/UserRepository.cs

But basically, what I'm wondering about is, why do it even make sense to use a repository here, instead of just writing it like this:

public class MainViewModel : ViewModelBase
{
    private ScorBotEntities context = new ScorBotEntities();         

    public MainViewModel()
    {
    }

    public ObservableCollection<User> Users
    {
        get
        {
            return new ObservableCollection<User>(context.Users);
        }
    }
}

It makes sense to abstract functionality away such as with the UsernameAndPassword method. But in that case, perhaps using some Query Objects would be more ideal?

+1  A: 

Separation of concerns

What if you want to change the storage of 'Users', from say SQL to a flat file?

Then context would not be needed, and you'd have to change every use of it, instead of just your IRepository implementation.

Also, ideally you would have your IRepository injected. So you're MainViewModel doesn't care how it gets it's Users.

PostMan
Yeah, I'm playing around. I used to have it injected, but since I also had the context injected again to the repository, it suddenly meant the *view* was initializing the database -- which I didn't find a good idea. If you got any ideas for that, I would love to hear them.
Claus Jørgensen
Take a look at Ninject, with this, at `Application ` (if you're using MVC) you bind each interface to it's implementation then use your container to return whatever you need.
PostMan
`Application_Start`* - For some reason I can't edit my comment
PostMan
+2  A: 

I am a bit baffled that your context has made its way down to your ViewModel. I believe your GUI layer should never see the context. Context must be opened/kept/closed by the IRepository. Let the data layer (IRepository) return an array/list of Users.

Aliostad
That's part of my concern as well. But this means the repository implementations gets hard coupled with the context. I thought that was a *bad* thing.
Claus Jørgensen
Dealing with the data/context is the main/only concern for the repository. Don't shy away from coupling them together. Alternative is wrapping your database access (context access here) which I would say is unnecessary.
Aliostad
But this means the testability of the repository disappears entirely, and that I can't share the data/context between several repositories. It doesn't seem very optimal. Also, if the context is opened/closed at each request, then the entire repository might as well be static.
Claus Jørgensen
Testing IRepository - based on my personal experience - is coupled with the backing database. I always use repository to insert, update and delete and check the results. There should really not be more than one context at a time. The issues you see while you try to save entities back while context has been closed and you end up attaching/detaching and doing hundred more unnecessary things, is not your fault - it is EF. EF is the result of a BAD BAD design. I would have stayed within 100 miles radius of EF and used NHibernate if I had the liberty to do so :)(
Aliostad
+2  A: 

There are a couple of different points here. First, your view models should have no knowledge of the repository - keep your view models as simple as possible.

Second, the IRepository is your public API - so you should have dependencies to this (depend on abstractions rather than concrete implementation between layers).

There are a couple of different (perfectly acceptable ways) to implement the IRepository. One is to have the repository encapsulate the context directly. Another is to use the "unit of work" pattern and have your unitOfWork encapsulate the context and pass the unitOfWork object to each repository. Either way, since you're using EF4, testability is much easier than it used to be. For example, EF4 introduced IObjectSet so that it is easy to provide test doubles and mocks to test your repository.

I highly recommend checking out this whitepaper on Testability and Entity Framework 4.

Steve Michelotti
In MVVM, the ViewModel is also partially controller, so it's the correct place to resolve the repository, and fill out the view. But everything points towards using IoC, which will move the database initialization and disposing to the Application entry point. I think that might be the best solution.
Claus Jørgensen