Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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>(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 field the copy of MobileOrderSettings). Is this approach is good, or you can suggest any better solution?

share|improve this question
up vote 1 down vote accepted

Two possible sources of errors:

  1. 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).
  2. 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.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.