HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Cloning Entity Framework entities

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
cloningframeworkentitiesentity

Problem

I'm currently writting piece of logic which copies entities from one user account to another. My current strategy in doing this is like that:
Consider the following code:

public class MobileOrderSettings:ICloneable
{
    public long Id { get; set; }
    public bool allowCash { get; set; }
    public int deliveryPrice { get; set; }
    public int deliveryTreshold { get; set; }
    public bool orderingEnabled { get; set; }
    public bool paymentsEnabled { get; set; }
    public int shippingType { get; set; }

    public virtual MobileApp MobileApp { get; set; }

    public object Clone()
    {
        var copy = CopyUtils.ShallowCopyEntity(this);
        copy.Id = default(int);
        copy.MobileApp = null;
        return copy;
    }
}


The ShallowCopyEntity method defined like in this way:

public static TEntity ShallowCopyEntity(TEntity source) where TEntity : class, new()
    {

        // Get properties from EF that are read/write and not marked witht he NotMappedAttribute
        var sourceProperties = typeof(TEntity)
                                .GetProperties()
                                .Where(p => p.CanRead && p.CanWrite &&
                                            p.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.Schema.NotMappedAttribute), true).Length == 0);
        var notVirtualProperties = sourceProperties.Where(p => !p.GetGetMethod().IsVirtual);
        var newObj = new TEntity();

        foreach (var property in notVirtualProperties)
        {

            // Copy value
            property.SetValue(newObj, property.GetValue(source, null), null);

        }

        return newObj;

    }


So, as you can see, I firstly copy all fields which is not virtual, reassing Id value and then perform copy of the dependent object(collection)(In this particular situation MobileOrderSettings depends on MobileApp entity, so I make MobileApp null, and in MobileApp Clone menthod I assign MobileOrderSettings virtual fiel

Solution

Two possible sources of errors:

  • If you forget to use (or don't want to apply) the virtual modifier, it will no longer be a shallow copy (because virtual is typically used for navigation properties).



  • It relies on unmapping properties by attributes. If at any time in the future you start using the fluent API for that purpose you'll change behavior in an unexpected place.



You evidently want to clone mapped and scalar properties only. Your approach works (if you remember the error sources), but I'd prefer to use a method provided by EF itself:

MobileOrderSettings settings = context.MobileOrderSettings.FirstOrDefault();
var shallowCopy = (MobileOrderSettings)context.Entry(settings)
                                              .CurrentValues.ToObject()


As you see, the CurrentValues property of an entry in EF's change tracker is used to build a clone, which is always a shallow clone of mapped properties.

Of course, you can't apply this method inside an entity class, because it requires a context to which the entity object is attached. But is that bad? I'd say no, because this clone method has a very specific purpose which is tied to an EF environment. To me it would break the persistence ignorance principle if a class would require knowledge of the data layer implementation for which it clones itself.

Code Snippets

MobileOrderSettings settings = context.MobileOrderSettings.FirstOrDefault();
var shallowCopy = (MobileOrderSettings)context.Entry(settings)
                                              .CurrentValues.ToObject()

Context

StackExchange Code Review Q#125149, answer score: 9

Revisions (0)

No revisions yet.