Search code examples
entity-frameworkintegration-testingautomappercode-first

How can I create a detached clone of an EF codefirst class for testing purposes?


I want to create an integration test which grabs an EF entity from the DB, clones it to a detached object, modifies it and then saves it back and compares it again to the original.

However, I was using AutoMapper to create the clone of the class, but it turns out this is also tracked or an alias to the original object. I need it to be completely detached from EF, and am able to do this outside of my repository class (i.e. not using any EF detach methods).

The reason for doing this is my EF class contains nested collections of other classes and EF doesn't handle persisting the whole object tree. Hence, my Update() method in my repository class handles this and I want my NUnit test to test this code. I want the test is to be able to quickly create a copy of my original class without EF tracking it.


Solution

  • If it is a test you can do anything and you don't have to be binded to any architectural approach like repository. Your repository probably receive context as injection so you can have access to it. Another point is that I don't believe that AutoMapper will create tracked entity.

    The one way to make a copy of the class is using serialization which by default saves only public fields (Xml serialization or DataContract serialization). Serialize the object and deserialize it back to a new instance. Serialization will save the whole object graph and deserialized object graph will be detached. Just be aware that that those serializations don't likes cyclic references in object graph (navigation property from A to B and from B to A from cycles). Serialization is also too much aggresive so it can traverse the graph more deeply then you want - this can be especially dangerous in many to many relations.

    The best approach is using either ICloneable interface and implement Clone or define support methods which will do different clones with required depth.

    Here is another approach for clonning EntityObject based entities. It is tough code, especially part with Reflection.Emit. But this will not help you because code-first is using POCOs.