深度克隆代码首先是EF实体

时间:2017-06-14 20:28:56

标签: c# entity-framework reflection entity-framework-6 clone

我正在为代码优先实体框架实体尝试通用深度克隆例程。

我已经针对标准系统属性类型破解了它,但是我遇到了代理实体(用虚拟定义)的问题,即

[EntityLookup]
public virtual Person { get; set; }

[EntityLookup]是我自己的一个属性,有助于进一步定义关联。

如果我删除“virtual”关键字,我的例程可以更新目标实体属性没问题(但我失去了额外的EF功能) 使用虚拟时,我收到以下错误;

System.Reflection.TargetException: 'Object does not match target type.'

我认为这与EF的Proxy类有关,但我不确定如何转换原始实体,以便我可以在目标上设置它。 以下是此问题的克隆例程的基本要点;

public static void CloneProperties<T>(T Original, T Destination)    
{
    PropertyInfo[] props = Original.GetType().GetProperties();
    foreach (var propertyInfo in props)
    {
        if (propertyInfo.PropertyType.Namespace == "System" || propertyInfo.PropertyType.IsEnum)....
        else
        {
                if (Destination.PropertyHasCustomAttribute (propertyInfo.Name, typeof(EntityLookupAttribute)))
                {
                    var pv = propertyInfo.GetValue(Original, null);
                    propertyInfo.SetValue(Destination, pv, null);
                }
         }
    }
}

这是“propertyInfo.SetValue(Destination,pv,null);”当实体被声明为虚拟时生成错误。

感谢您接受任何有关上班的帮助

最好的问候

兰斯

此外,我也正在尝试克隆我实体中的子集合。

我正在迭代源属性集合,需要将缺少的记录添加到目标属性集合

a.Add(targetEntity); line出现以下错误;

"The best overloaded method match for 'System.Collections.ObjectModel.Collection<FmCosting.Entities.CsJobDetail>.Add(FmCosting.Entities.CsJobDetail)' has some invalid arguments"

相关代码是;

                if (dest.PropertyHasCustomAttribute(propertyInfo.Name, typeof(EntityChildCollectionAttribute)))
                {
                    var source = propertyInfo.GetValue(original, null) as ICollection;
                    var target = propertyInfo.GetValue(dest, null) as ICollection;
                    foreach (dynamic sourceEntity in source)
                    {
                        var found = false;
                        object targetEntity = null;

                        foreach (dynamic tEntity in target)
                        {
                            if (sourceEntity.IdentityGuid == tEntity.IdentityGuid)
                            {
                                found = true;
                                targetEntity = tEntity;
                                continue;
                            }

                        }

                        if (!found)
                        {
                            var t = sourceEntity.GetType();
                            targetEntity = Activator.CreateInstance(t);
                        }


                        sourceEntity.CloneMeToProvidedEntity(targetEntity);

                        if (!found)
                        {
                            dynamic a = target;
                            a.Add(targetEntity);
                        }


                    }
                    //propertyInfo.SetValue(Destination, pv, null);
                }

将非常感激地收到任何进一步的帮助

最好的问候

兰斯

2 个答案:

答案 0 :(得分:1)

destination对象的具体类型可能与T不同,因此您必须使用PropertyInfo destination而不是original }:

public static void CloneProperties<T>(T original, T destination)    
{
    var originalType = original.GetType();
    var destinationType = destination.GetType();

    PropertyInfo[] props = originalType.GetProperties();
    foreach (var propertyInfo in props)
    {
        if (propertyInfo.PropertyType.Namespace == "System" || propertyInfo.PropertyType.IsEnum)
        {
            // ....
        }
        else
        {
            if (destination.PropertyHasCustomAttribute (propertyInfo.Name, typeof(EntityLookupAttribute)))
            {
                var pv = propertyInfo.GetValue(original, null);
                var destinationProperty = destinationType.GetProperty(propertyInfo.Name);
                destinationProperty.SetValue(destination, pv, null);
            }
         }
    }
}

注意:

另一种选择是恢复编译时间类型,因此两个对象都使用T的属性来避免可能从GetType()返回的派生类型:

public static void CloneProperties<T>(T original, T destination)    
{
    PropertyInfo[] props = typeof(T).GetProperties();
    foreach (var propertyInfo in props)
    {
        if (propertyInfo.PropertyType.Namespace == "System" || propertyInfo.PropertyType.IsEnum)
        {
            // ....
        }
        else
        {
            if (destination.PropertyHasCustomAttribute (propertyInfo.Name, typeof(EntityLookupAttribute)))
            {
                var pv = propertyInfo.GetValue(original, null);
                propertyInfo.SetValue(destination, pv, null);
            }
         }
    }
}

答案 1 :(得分:0)

我使用IList进行了集合克隆,如果它可以帮助其他任何人,这里是相关的代码。

if (dest.PropertyHasCustomAttribute(propertyInfo.Name, typeof(EntityChildCollectionAttribute)))
{
    var source = propertyInfo.GetValue(original, null) as IList;
    var target = propertyInfo.GetValue(dest, null) as IList;
    foreach (dynamic sourceEntity in source)
    {
        var found = false;
        object targetEntity = null;

        foreach (dynamic tEntity in target)
        {
            if (sourceEntity.IdentityGuid != tEntity.IdentityGuid) continue;
            found = true;
            targetEntity = tEntity;
            break;
        }

        if (!found)
        {
            var b = propertyInfo.PropertyType.GetGenericArguments()[0];
            targetEntity = Activator.CreateInstance(b);
        }

        sourceEntity.CloneMeToProvidedEntity(targetEntity);

        if (!found)
        {
            target.Add(targetEntity);
        }
    }
}