Pergunta

Currently working on an MVC application using the MVVM pattern. It was originally written so that all the ViewModels inherited from the same BaseViewModel, which spun up a single Entity Framework repository, like so:

public abstract class BaseViewModel : INotifyPropertyChanged
{
    private static MyRepository _rep;
    protected static MyRepository rep
    {
        get
        {
            if (_rep == null)
                _rep = new MyRepository();
            return _rep;
        }
    }
}

The application as I inherited it had virtually no unit testing, so I decided to do some refactoring to make it more testable. So I put an interface over the repository, and gave each viewmodel its own copy, so it could be mocked out for testing:

public class MyViewModel : BaseViewModel
{
    private IMyRepository _rep;

    public AvailabilityHistoryViewModel()
        : this(new MyRepository())
    { }

    public MyViewModel(IMyRepository rep)
    {
        _rep = rep;
        DoStuff();
    }
}

Which is fine for the majority of cases. But then I came across a previously functional button that suddenly caused the application to crash with the dreaded "entity object cannot be referenced by multiple instances of IEntityChangeTracker" error.

It turns out that there's a UserControl that's used in several places in the application which also inherits from BaseViewModel and so has its own copy of the repository.

public abstract class BaseTreeViewItem : BaseViewModel
{ }

When this is used inside a parent viewmodel, and its properties are passed around, it's quite possible to end up with an EF object that's been created with the UserControl repository being passed to the ViewModel and saved with its repository - which, because they're different contexts, causes the crash.

The easy fix is simply to back out my changes, and have the ViewModels that use this UserControl go back to using the BaseViewModel repository. But that's ugly. A proper fix for this, rearranging things so that the UserControl doesn't have its own context, is going to take longer that I've realistically got. Is there another way?

Foi útil?

Solução

I might miss something, but it seems to me that having singleton repositories would solve your problem. You already use them through interface, so you could simply inject them.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top