Home > .net 3.0, .net 3.5, c#, LINQ, Microsoft, Visual Studio 2008 > Deep Copy Cloning of LINQ Entity Objects

Deep Copy Cloning of LINQ Entity Objects

June 4, 2008

Unfortunately, there’s no real slick way (built into LINQ) to clone LINQ entity objects. 

My need was simple:  Take a record, duplicate it, change a few select values, and then dump it back into the data source to generate a new primary key.

But I couldn’t find a good way to get a deep copy using ICloneable and sure as heck didn’t want to do it manually. 

After a bit of searching, I came across a great blog posting that discussed using direct IL to make deep copies of objects.  The blog post looked promising.  As the author explains, “[t]he basic thing that it does is, create a DynamicMethod, get the ILGenerator, emit code in the method, compile it to a delegate, and execute the delegate.”  Sounds simple enough.

NOTE: Check out the blog post (here) for the full source code; the modifications I made are mostly domain specific—the implementation works great as it is.

I added the method into the GenericController that I use to implement LINQ and the results were brillant!

// Clone the entity based on the original report.

var newReport = this.Clone(SelectOne(originalReportId));

           

// Remove the ID to make it generate a new primary key.

newReport.Id = 0;

           

//  Change the necessary information.

newReport.EnteredBy = enteredBy;

newReport.Quarter = quarter;

 

// Insert the imported report into the system and save changes.

Insert(newReport, true);

 

// Now that the imported report has a primary key, return it.

return newReport;

Because .Clone is a virtual method of my Controller’s base class (public virtual T Clone<T>(T entity)), it applies to any type that I happen to pass into it.  In the code example above, this Import method is in the ReportsController and SelectOne returns a Report object, so Clone generates a clone based on the constructor and fields of that type.  Implementation with any other LINQ controller works just the same—excellent for reuse.

Since an integer primary key, Id in the code above, cannot be null, setting it to zero (0) will force the SQL processor to generate a new primary key when the record is entered into the database—which is exactly what we want.

Very pleased with the implementation of this and how slick (and quickly) it works.

Tags: , , , ,
  1. June 5, 2008 at 8:42 am

    Interesting article.

    I’ve taken a similar approach in terms of enabling cloning of cached entities, but was actually quite surprised to see that the IL implementation was faster. I was under the impression that once you’ve got a reference to the cached entity, calling a Clone() method would be as fast (or faster) than asking a delegate to do the same thing.

    The mind boggles.

    If you decide to take the IL / delegate cloning route, it would probably be best to use an attribute to mark properties as cloneable (the LINQ to SQL “Column” attribute comes in handy here – and is autogenerated by the designer). This prevents the cloning of unwanted properties that may have been added to the entity for things like state management or version tracking).

    Related to the IL / delegate combination I’ve succesfully replaced reflection based code (used to instantiate fields that reside in lists / rows of types that are unknown at compile time). This implementation allowed any configurable field types to perform like first class citizens in the API – a truly impressive technique I must say.

    I’ve been meaning to blog a bit about the above thoughts, but it seems like the net is littered with IL / delegate articles these days.

    Thanks for posting,
    Anders.

  2. Sam
    June 16, 2008 at 7:09 am

    Cloning of contained EntitySets does not work😦

    If I clone an entity with an EntitySet (1:m-relation), it will only be a very shallow copy, means, if after cloning I add or remove an item to or from the EntitySet, it will be removed from the clone, too.

    (the copy does not need to be deep, but at least cloning the collection itself would be very helpful)

    Anyway, great code!

  3. June 16, 2008 at 7:25 am

    @Sam-

    Saw your comment on the updated post–yeah, what a bummer. I’ve been dragged off to other tasks both at work and home, so I haven’t had time to dig deep into ways around this. My first thought would be to look at the FieldInfo and if it implements IEnumerable, then dig into that. I’m just not sure what’d that do to performance and if I’d simply find myself in these HUGE loops when the FK relationship contains another FK relationship–etc.

    The joys of development.🙂

  4. June 17, 2008 at 1:19 am

    I’m currently working on a new version of the IL Cloning mechanism, one that allows to really deepclone objects…
    I’m also considering the use of Custom Attributes to exclude certain objects from being cloned. Or to say that a shallow copy is needed or a deepcopy of a property/field.

    The only ‘constraints’ that I encountered so far is the fact that the ‘to-clone’ object MUST have a constructor, because the system will create a new instance.
    In a later version I will try to solve it by detecting properties and arguments in the constructor (if they are named almost the same with other casings).

    But that’s the future, in first instance I will implement the 1 level deep cloning, and if that works quick enough, I’ll implement the N-level cloning,
    trying to exclude system variables, from for example LINQ objects.

    It’s a challenge, and I’m up for it😉

    I’ll post the solution on my blog when it’s finished and stable enough…

    PS: Thanks for referencing my post😉

    Regards,
    F.

  5. June 2, 2009 at 9:42 am

    Is there any reason why you didn’t just do the following?

    context.Detach(obj);
    obj.EntityKey = null;
    obj.MyChangingProperty = “NewValue”;
    context.AttachToMyObjs(obj);
    context.Save

    It appears to give the same results as cloning and was much more simple.
    Richard

  1. June 5, 2008 at 1:20 pm
Comments are closed.
%d bloggers like this: