7

I've been working on my ASP.NET MVC application for months now. When I first started working on it I was using Entity Framework 4.3 (Code-First w/Migrations). While I was doing so I ran into some problems trying to do updates on my MainClient table. MainClient contains all of a client's basic information, and has a 1:1 relationship with the BPClient table, which contains more specific information about that client pertaining to their license agreement for the BP module. Both of which can be edited on the same page in a tab control. However, I kept on getting the following exception when trying to change the EntityState of the MainClient object to being EntityState.Modified:

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

I noticed while debugging that the object itself was considered Detached when it went into my Controller class to be saved. As a workaround for this issue, I applied a similar solution to the problems found in this blog post and in this SO question. Here's how the code for re-attaching the objects looked afterwards (messy, I know), given the Edit method being passed in a MainClient object called client:

var newClientObject = new MainClient { ClientID = client.ClientID };
Db.MainClients.Attach(newClientObject);
Db.Entry(newClientObject).CurrentValues.SetValues(client);

var bpClient = new BPClient { ClientID = client.ClientID, BaseClient = newClientObject };
if (client.BPClient != null)
{
    Db.BostonpostClients.Attach(bpClient);
    Db.Entry(bpClient).CurrentValues.SetValues(client.BPClient);
}

Db.SaveChanges()

This worked just fine and dandy through all test cases. Up until recently.

Recently, I upgraded my application to use Entity Framework 5 (still using Code-First). When I was testing the MainClient edit page again, though, I found some rather erratic behavior. Some fields, when edited, would be saved without problems. Others would never be committed to the DB. Still others would persist fine, but only if they were the only part of the object being edited. I debugged the heck out of the DbContext that was in the Controller class, and found, rather annoyingly, that not only were the changes made on the page being sent to the Controller class, but that the ObjectStateManager had both the MainClient and BPClient objects in it with the changes that had been made on the page as well! I should mention here, by the way, that I didn't receive one error while debugging it, not even after SaveChanges().

I decided to try and revert the code to what it had been originally, that is to say the logical way of doing it:

Db.Entry<BPClient>(client.BPClient).State = EntityState.Modified;
Db.Entry<MainClient>(client).State = EntityState.Modified;

Db.SaveChanges();

And now it works totally fine. No InvalidOperationException. So that's been solved just fine.

What's still bothering me is trying to figure out just what changed in 5.0 that made my earlier fix stop working and go all wonky on me. Why did that code work fine in 4.3 but not in 5.0? What in 5.0 made committing to the database with that code so erratic?

Does anybody know why this would have happened?

Community
  • 1
  • 1
Corey Adler
  • 15,897
  • 18
  • 66
  • 80
  • It might be help you. Entity Framework 5 Enums and Moving Solution from EF 4.3 http://thedatafarm.com/blog/data-access/video-entity-framework-5-enums-and-moving-solution-from-ef-4-3/ – Aru Nov 14 '14 at 15:14

1 Answers1

0

I had this issue myself. I was using IDbSet classes to populate database tables, what I found was when I made a property virtual EF5 performs a lazy load (my virtual properties where other objects in the database). This means that I recieve a new primary key for the virtual property. Well if I do not have a specific id associated with the object I want to reference EF 5 tries to make a two way relationship. If you do not specifically tell EF which property to map to in the DBContext It sets up two foreign keys to the same object which is not allowed. Hope this helps.

Robert
  • 4,306
  • 11
  • 45
  • 95
  • Thanks for trying to answer my question. I don't think that this is the case here, though. I've already set up the 1:1 between MainClient and BPClient as a two way relationship (both with virtual properties as well as IDs). I'm just trying to figure out why the code all of a sudden stopped working. – Corey Adler Dec 26 '12 at 18:46
  • using only virutal properties causes lazy loading, do you have the same map done in your dbcontext between the properties? – Robert Dec 26 '12 at 19:40
  • I'm using Data Annotation, not the FLuent API. The mapping is entirely on the object itself, not in the DbContext. Did something happen between 4.3 and 5.0 in regards to lazy loading that would have affected the code in such a way? – Corey Adler Dec 26 '12 at 19:44
  • On an app I just completed we changed from 4.3 to 5.0 and as stated above if you attempt to lazy load and map then you get two keys. The way we fixed it was to have an int fooId and a int barId property that we mapped directly in the dbcontext and we did not do any lazy loading because EF tries to do multiples and in some instances it is unable to choose which one. – Robert Dec 26 '12 at 20:00