Cloning an entity in linq-to-entities

making a clone of a record and popping it back into the database

There are a lot of reason you may want to do something like this, for me, users wanted to be able to make a copy of a huge record so they would then be able to go in and change a few things rather than make a whole new record which was very time consuming. At first, I though of pulling the item, manually copying each property, and inserting… but this is programming, there must be a better way. So then I thought about Reflection and how I might be able to work with that, but that became a big mess that I never got working prior to being discouraged. Next I hit Google, and an awesome blog had a great post to get me on the right track:http://damieng.com/blog/2009/04/12/linq-to-sql-tips-and-tricks-2.

That solution used Serialization to clone the entity, so simple, and so effective. The example they used there was Linq-to-SQL, but it will work for Linq-to-Entities just the same. I modified the code slightly to be used as an extension to basically any type… as this can really clone almost anything you throw at it (I think):

public static T Clone<T>(this T source)
{
  var dcs = new System.Runtime.Serialization
    .DataContractSerializer(typeof(T));
  using (var ms = new System.IO.MemoryStream())
  {
    dcs.WriteObject(ms, source);
    ms.Seek(0, System.IO.SeekOrigin.Begin);
    return (T)dcs.ReadObject(ms);
  }
}

That simple little bit of code will now clone *anything* – perfect! Now is just how to push it back into the db, which can be a little confusing. Initially, I tried this, which was intuitive to me:

MyEntities db = new MyEntities();
note n = db.note.First(nt => nt.note_id == some_int); 
note new_n = n.Clone();
db.AddTonote(new_n);
db.SaveChanges();

But was met with this error:

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

But, after actually thinking about it, that makes sense, sincenew_n is the same *exact* object as n, I can’t really insert it into the DB, it is basically confusing the two. So to get around that, you have to detach the original Entity:

using (MyEntities db = new MyEntities())
{
  note n = db.note.First(nt => nt.note_id == some_int);
  note new_n = n.Clone();
  db.Detach(n);
  db.AddTonote(new_n);
  db.SaveChanges();
}

Closer, but still did not work, I now got the following error:

The object cannot be added to the ObjectStateManager because it already has an EntityKey. Use ObjectContext.Attach to attach an object that has an existing key.

Which also makes sense as you can’t insert an Entity that already has an EntityKey. So one final change and we have a working clone:

using (MyEntities db = new MyEntities())
{
  note n = db.note.First(nt => nt.note_id == some_int);
  note new_n = n.Clone();
  db.Detach(n);
  new_n.EntityKey = null;
  // make any other changes you want on your clone here
  db.AddTonote(new_n);
  db.SaveChanges();
}

And no we have successfully cloned a record (Entity) and put a copy into the database. This would work very similarly for Linq-to-SQL, but I have not implemented it quite yet.

Leave a comment