3

The navigation properties on my entity are causing my deep clone to fail with the error:

"An object with the same key already exists in the ObjectStateManager"

Background:

Users want to be able to clone a parent record and all its associated child records. I'm able to clone the parent entity alone (with no errors) using this simple technique:

_context.Detach(currentParentEntity);
_context.AddToParentEntities(currentParentEntity);
_context.SaveChanges();

I found that solution and another working shallow clone technique (from diamandiev) here.

Since what I really need is a deep copy I've tried implementing the serialization cloning technique shown here, here and here. My calling code looks like this:

ParentEntity clonedParentEntity = (ParentEntity)DeepClone(currentParentEntity);
_context.Detach(currentParentEntity);
clonedParentEntity.EntityKey = null;
_context.AddToParentEntities(clonedParentEntity);
_context.SaveChanges();

This code only works when cloning a currentParentEntity with no child entities (referenced in navigation properties). If child entites exist I get the "object with the same key already exists" error. Why? How can I deep clone both a parent entity and it's associated child entities then save the cloned record without any errors?

Thanks in advance.

EDIT: For the complete accepted answer read Ladislav Mrnka's answer plus the comments.

Community
  • 1
  • 1
DeveloperDan
  • 4,626
  • 9
  • 40
  • 65

1 Answers1

2

If you really used serialization you cloned both parent and child entities - that is not your problem. Your problem is calling Detach because it will remove only single entity you are detaching (not its children). So the error is caused by adding children with same keys already tracked by the context.

Ladislav Mrnka
  • 360,892
  • 59
  • 660
  • 670
  • That makes sense. Now I could use some help with how to detach the child entities and then save the cloned record without errors. Any suggestions on where I might find a good code sample? The samples I've found are incomplete. – DeveloperDan Jul 14 '11 at 12:27
  • There is probably not such a sample. The easiest way is create clone and add it to a new instance of the context. – Ladislav Mrnka Jul 14 '11 at 12:39
  • 1
    Using a new context works. Thanks! After calling SaveChanges with the new context I re-query the original context to display the cloned record. I had to be sure to call Dispose on the new context or I got an error while modifying the new record: "The relationship between the two objects cannot be defined because they are attached to different ObjectContext objects." Context.Dispose was needed on the new context even though I declared it in a Using statement. Problem solved. StackOverflow rocks! – DeveloperDan Jul 14 '11 at 17:25
  • @DeveloperDan Can you show the working example? and the extension method you are using please. – Obsivus May 10 '12 at 07:03