views:

40

answers:

1

I am trying to add functionality in my ASP.NET MVC app to change some fields of my data structure. After clicking the submit button on the form, the following action is called:

    [HttpPost]
    public ActionResult Edit(Document doc)
    {
        // Attempt to save the project
        if (_documentService.SaveDocument(doc) == ServiceActionResult.Success)
            return RedirectToAction("List");
        else
            return View();
    }

The SaveDocument() method looks like this:

    public ServiceActionResult SaveDocument(Document doc)
    {
        if (doc == null)
            return ServiceActionResult.ActionFailure;

        // Check if this is a new Document (null ID)
        if (doc.Id == 0)
            _documentRepository.Add(doc);
        else
            _documentRepository.Attach(doc);

        _documentRepository.SaveChanges();

        return ServiceActionResult.Success;
    }

Since the document exists (and thus has an Id value), I call the Attach() method of my generic repository. The attach method just looks like:

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

When the object set's Attach() method is called, the following exception occurs:

An object with the same key already exists in the ObjectStateManager. The ObjectStateManager cannot track multiple objects with the same key.

I don't understand why this is happening, since as you can see the whole lifecycle of the request only has one call to EF, and that's the final Attach(entity) call. Am I missing something?

As an FYI, this system used to work, but what seems to have broke it was my conversion from model first to code first with POCOs (latest CTP). All my other functionality works just as it did before, except for this scenario.

If it helps, my generic repository gets the ObjectSet from the DbContext via a function I wrote in my context class:

    public ObjectSet<T> CreateObjectSet<T>() where T : class
    {
        return ObjectContext.CreateObjectSet<T>();
    }


Edit: After looking around my code due to the comments I just remembered that I had implemented a singleton for context management. I did this due to the fact that it's possible a Controller may get entities from one service class, and use another service class to update it (I think that was the scenario I was trying to solve, I implemented it a while ago and I'd have to look closer when I get off of work).

I used a singleton for this because I had the impression that the singleton wouldn't go across multiple http requests, and I assume by the comments that that could be the issue. I'll look at this when I get home.

+3  A: 

RE: as you can see the whole lifecycle of the request only has one call to EF

As far as we can see from the code shown, the ObjectContext lifetime could be the lifetime of the application. If it is, then that's probably the issue here.

Can you explain how you manage the ObjectContext lifetime .. is it per Http Request?

Hightechrider
I am not sure how you would have an ObjectContext last for more than one Http request so that could be an issue, but how would I figure out my ObjectContext lifetime?
KallDrexx
Can you post the code for how you create the ObjectContext used in CreateObjectSet<T>(). When does it get created and released?
Hightechrider
I just updated the original question after doing a quick look at my object context code. After your comment I have a feeling it's cause I"m using a singleton pattern for my object context creation, so I have a feeling I'll have to change that.
KallDrexx
You probably want to scope it to the web request or smaller. Take a look at the many questions on the topic on SO for suggestions:- http://stackoverflow.com/search?q=objectcontext+lifetime
Hightechrider