代码优先 EF 实体的深度克隆
Deep Clone of code first EF Entity
我正在为代码优先 Entity Framework 实体尝试通用深度克隆例程。
我已经针对标准系统 属性 类型破解了它,但在使用代理实体(使用虚拟定义)时遇到了问题,即
[EntityLookup]
public virtual Person { get; set; }
[EntityLookup] 是我自己的属性之一,有助于进一步定义关联。
如果我删除 "virtual" 关键字,我的例程可以更新目标实体 属性 没问题(但我失去了额外的 EF 功能)
使用虚拟我得到以下错误;
System.Reflection.TargetException: 'Object does not match target type.'
我认为这与 EF 的代理有关 class 但我不确定如何转换原始实体以便将其设置在目标位置。
以下是针对此问题的 Clone 例程的要点;
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);行给出以下错误;
"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);
}
任何进一步的帮助将不胜感激
此致
兰斯
您的 destination
对象的具体类型可能与 T
不同,因此您必须使用 destination
的 PropertyInfo
而不是 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);
}
}
}
}
我使用 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);
}
}
}
我正在为代码优先 Entity Framework 实体尝试通用深度克隆例程。
我已经针对标准系统 属性 类型破解了它,但在使用代理实体(使用虚拟定义)时遇到了问题,即
[EntityLookup]
public virtual Person { get; set; }
[EntityLookup] 是我自己的属性之一,有助于进一步定义关联。
如果我删除 "virtual" 关键字,我的例程可以更新目标实体 属性 没问题(但我失去了额外的 EF 功能) 使用虚拟我得到以下错误;
System.Reflection.TargetException: 'Object does not match target type.'
我认为这与 EF 的代理有关 class 但我不确定如何转换原始实体以便将其设置在目标位置。 以下是针对此问题的 Clone 例程的要点;
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);行给出以下错误;
"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);
}
任何进一步的帮助将不胜感激
此致
兰斯
您的 destination
对象的具体类型可能与 T
不同,因此您必须使用 destination
的 PropertyInfo
而不是 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);
}
}
}
}
我使用 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);
}
}
}