我从DbEntityEntry.Entity
获取实体。这将返回实体的Entity Framework代理。
如何以基本对象的原始类型而非代理方式访问基础对象?
或者我需要动态尝试将代理转换为实体类型。这是一个开始..
var theEntityType = entityEntry.Entity;
if (theEntityType.BaseType != null && entityType.Namespace == "System.Data.Entity.DynamicProxies")
theEntityType = entityType.BaseType;
// Now I need to cast to the correct type
var entityObject = (theEntityType)entityEntry.Entity; // THIS WON'T WORK BECAUSE `theEntityType` is dynamic.
// My entites also don't implement IConvertible
答案 0 :(得分:41)
使用EF 6时,我使用以下代码从代理类型中获取基础POCO实体类型,
var entityType = ObjectContext.GetObjectType(dbEntitymodifiedEntry.Entity.GetType());
ObjectContext.GetObjectType
:从代理对象
参考:https://docs.microsoft.com/en-us/ef/ef6/fundamentals/proxies
答案 1 :(得分:33)
首先,我应该说没有潜在的对象。代理不会包装实体对象(装饰器模式),它从中派生(继承)。因此我们无法打开实体,我们只能将代理转换为基础对象。转换(与转换相反)始终会创建一个新对象。
对于这种转换,我们可以利用这样一个事实:在大多数情况下,通过EF返回代理的方式,代理的编译时类型是基本类型。也就是说,如果将代理作为参数输入到泛型方法,则泛型参数将被推断为基本类型。此功能允许我们创建一个满足您需求的方法:
T UnProxy<T>(DbContext context, T proxyObject) where T : class
{
var proxyCreationEnabled = context.Configuration.ProxyCreationEnabled;
try
{
context.Configuration.ProxyCreationEnabled = false;
T poco = context.Entry(proxyObject).CurrentValues.ToObject() as T;
return poco;
}
finally
{
context.Configuration.ProxyCreationEnabled = proxyCreationEnabled;
}
}
<强>解释强>
代理对象进入方法。其类型被推断为基础POCO类型。现在我们可以暂时关闭上下文中的ProxyCreationEnabled
并将代理对象复制到其基本POCO类型的对象。此复制操作非常感谢使用一些EF功能。
答案 2 :(得分:18)
如果您最终需要从无法访问EF或DBContext的项目中执行此操作,并且您不知道您引用的类型是否是代理,则可以执行以下操作:
public Type GetType
{
get
{
var thisType = _baseObject.GetType();
if (thisType.Namespace == "System.Data.Entity.DynamicProxies")
return thisType.BaseType;
return thisType;
}
}
答案 3 :(得分:4)
建议的答案有很多问题 - 例如,它不会保留在生成的POCO类的部分类中定义的属性,并且它会从DB重新加载实体(这也会影响性能)。
您可以尝试在请求更改之前关闭代理,但如果之前已经加载了实体,它可能无济于事 - 它们已经是代理类型(可能取决于EF版本,但它已经解决了)曾经在我的经历中没有再工作过)。 在转换代理之前,您还需要实现它 - 它不是显而易见的,但它只是延迟查询,必须具体化:
context.Configuration.ProxyCreationEnabled = false;
var changes = context.ChangeTracker.Entries().ToArray();
答案 4 :(得分:1)
使用AutoMapper 4.2.1它具有DynamicMap,可以从对象中删除代理。
var parents = parentsRepo.GetAll().ToList();
Mapper.CreateMap<Parent,ParentDto>();
var parentsDto = Mapper.DynamicMap<List<ParentDto>>(parents);
答案 5 :(得分:0)
要在EF Core中获得JSON友好对象,我使用了以下方法:
T UnProxy<T>(T efObject) where T : new()
{
var type = efObject.GetType();
if (type.Namespace == "Castle.Proxies")
{
var baseType = type.BaseType;
var returnObject = new T();
foreach (var property in baseType.GetProperties())
{
var propertyType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType;
if (propertyType.Namespace == "System")
{
var value = property.GetValue(efObject);
property.SetValue(returnObject, value);
}
}
return returnObject;
}
return efObject;
}