我正在为代码优先实体框架实体尝试通用深度克隆例程。
我已经针对标准系统属性类型破解了它,但是我遇到了代理实体(用虚拟定义)的问题,即
[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);
}
将非常感激地收到任何进一步的帮助
最好的问候
兰斯
答案 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);
}
}
}