0

I have made some architectural MVC-mistake since I did not know of the

An entity object cannot be referenced by multiple instances of IEntityChangeTracker.

error.

My setup is as follows: I have a repository for accessing the database which creates an instance of dbcontext, I have controllers that instantiate managers they need, the managers all instantiate their own repository. Here is the problem, when a controllers uses more than one manager to collect data and then try to create an object that uses this data, the error above appears when adding the object to the dbcontext.

I read about the UnitOfWork pattern, but it seems like a lot of work to restructure my code around that. Is there a quick fix to be able to update the database and avoid the error?

Thanks.

user2609980
  • 10,264
  • 15
  • 74
  • 143
  • Would be nice if you can include some code sample demonstrating your set up. Just include relevant code. BTW how does your managers instantiate dbContext, in using(){} construct? – SBirthare Mar 24 '15 at 05:07
  • To use one database context across your managers and repositories, you could pass it in when you instantiate them e.g. via the constructor – Colin Mar 24 '15 at 09:10
  • 1
    You can add some dependency injection mechanism, and create one `DbContext` per request. Then in repositories just get `DbContext` instance from IoC container, rather that create new one every time. With this approach you will not need to rewrite your repositories very much. – Aleksandr Ivanov Mar 24 '15 at 10:58
  • @sbirthare I will update the question this evening and let you know. Thanks. – user2609980 Mar 24 '15 at 11:19
  • @sbirthare, the repository instantiates a dBcontext and every manager has its own repository. There is no using block, the context is instantiated in the repository's constructor. – user2609980 Mar 24 '15 at 11:39
  • @aleksandrivanov Thanks. I will try using a IoC container or other solution for storing the context per request like http://stackoverflow.com/questions/6334592/one-dbcontext-per-request-in-asp-net-mvc-without-ioc-container. Thanks for the idea. – user2609980 Mar 24 '15 at 11:44

1 Answers1

1

I think that one of the ways to fix your problem in quick way will be to add dependency injection. Of course in ideal world repositories should have only DbContext instance and do not know nothing about how it was created.

You have not provided any code samples so I will present very simple examples.

In this example Autofac is used as IoC container. Write this code in Global.asax.Application_Start method.

var builder = new ContainerBuilder();
builder.RegisterType<YourDbContext>().As<IYourDbContext>().InstancePerRequest();

And then in your repository:

public class Repository1
{
    public IYourDbContext DbContext { get; private set; }

    public Repository1()
    {
        // How it's probably have been before
        // DbContext = new YourDbContext();

        // Getting DbContext from IoC container
        DbContext = (IYourDbContext) DependencyResolver.Current.GetService(typeof (IYourDbContext));
    }
}

If you don't want to add extra libraries, you could save DbContext instance at HttpContext.Current.Items.

Aleksandr Ivanov
  • 2,778
  • 5
  • 27
  • 35
  • Thanks! This seems like what I need. I am running on Mono an autofac seems I have some difficulties with that judging from a search but I will find a way. Why IDbcontext? – user2609980 Mar 24 '15 at 11:48
  • My bad, there is no such thing like `IDbContext`, I changed that in my answer. But it is always a good idea to have interface property for objects like `DbContext`, like in my example `IYourDbContext`. This approach will simplify future changes and makes code much easier to test. – Aleksandr Ivanov Mar 24 '15 at 21:11
  • How do I dispose the DbContext? – user2609980 Mar 25 '15 at 19:52
  • The `DependencyResolver.Current.GetService` always returns null. Do you know how to solve this? – user2609980 Mar 25 '15 at 20:19
  • Alright, using the concrete implementation instead of the interface (i.e. `builder.RegisterType().As().InstancePerHttpRequest();`) works, but I still get the error `An entity object cannot be referenced by multiple instances of IEntityChangeTracker.`. – user2609980 Mar 25 '15 at 20:25
  • Please read [this article](http://autofac.readthedocs.org/en/latest/integration/mvc.html) and check if your autofac configuration is correct. These 2 lines are important: `var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container));`. And you don't need to worry about disposing objects, autofac will do it for you automatically. – Aleksandr Ivanov Mar 25 '15 at 23:57
  • Also note, that I changed `InstancePerHttpRequest` (which is used for Web API) to `InstancePerRequest`. Sorry for confusion. If you will not use interface you don't need to use `As<>`, just leave it to be `builder.RegisterType().InstancePerRequest();`. – Aleksandr Ivanov Mar 26 '15 at 00:04