C# 从实体框架代理获取基础实体对象
通过从C# 从实体框架代理获取基础实体对象,c#,entity-framework,C#,Entity Framework,通过从DbEntityEntry.entity获取实体,我得到了一个实体。这将返回实体的实体框架代理 如何以原始类型而不是代理访问基础对象 或者,我需要动态地尝试将代理强制转换为实体类型。这是一个开始 var theEntityType = entityEntry.Entity; if (theEntityType.BaseType != null && entityType.Namespace == "System.Data.Entity.DynamicProxies")
DbEntityEntry.entity
获取实体,我得到了一个实体。这将返回实体的实体框架代理
如何以原始类型而不是代理访问基础对象
或者,我需要动态地尝试将代理强制转换为实体类型。这是一个开始
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
首先,我应该说没有底层对象。代理不包装实体对象(装饰器模式),而是从实体对象派生(继承)。因此,我们无法展开实体,只能将代理转换为基础对象。转换(与强制转换相反)总是创建一个新对象 对于这种转换,我们可以利用这样一个事实:大多数情况下,通过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;
}
}
T UnProxy(DbContext上下文,T proxyObject),其中T:class
{
var proxycreasonenabled=context.Configuration.proxycreasonenabled;
尝试
{
context.Configuration.ProxyCreationEnabled=false;
T poco=context.Entry(proxyObject).CurrentValues.ToObject()作为T;
返回poco;
}
最后
{
context.Configuration.proxycreasonenabled=proxycreasonenabled;
}
}
解释
代理对象进入该方法。其类型被推断为基本POCO类型。现在,我们可以暂时关闭上下文上的
ProxyCreationEnabled
,并将代理对象复制到其基本POCO类型的对象。此复制操作非常感谢地使用了一些EF功能。建议的答案有很多问题-例如,它没有保留生成的POCO类的分部类中定义的属性,并且它从DB重新加载实体(这也会影响性能)
在请求更改之前,您可以尝试关闭代理,但如果实体之前已经加载过,则可能没有帮助-它们已经是代理类型(可能取决于EF版本,但它只运行了一次,在我的经验中,下一次不起作用)。
在返回代理之前,您还需要具体化它-这并不明显,但它只是必须具体化的延迟查询:
context.Configuration.ProxyCreationEnabled = false;
var changes = context.ChangeTracker.Entries().ToArray();
在使用EF 6时,我使用以下代码从代理类型获取底层POCO实体类型
var entityType = ObjectContext.GetObjectType(dbEntitymodifiedEntry.Entity.GetType());
ObjectContext.GetObjectType
:从代理对象返回POCO
引用:如果您最终需要从一个无法访问EF或DBContext的项目中执行此操作,并且您不知道所引用的类型是否是代理,则可以执行以下操作:
public Type GetType
{
get
{
var thisType = _baseObject.GetType();
if (thisType.Namespace == "System.Data.Entity.DynamicProxies")
return thisType.BaseType;
return thisType;
}
}
使用AutoMapper 4.2.1它具有DynamicMap,可以从对象中删除代理
var parents = parentsRepo.GetAll().ToList();
Mapper.CreateMap<Parent,ParentDto>();
var parentsDto = Mapper.DynamicMap<List<ParentDto>>(parents);
var parents=parentsRepo.GetAll().ToList();
CreateMap();
var parentsDto=Mapper.DynamicMap(父级);
为了在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;
}
T取消固定(T efObject),其中T:new()
{
var type=efObject.GetType();
if(type.Namespace==“Castle.Proxies”)
{
var baseType=type.baseType;
var returnObject=new T();
foreach(baseType.GetProperties()中的var属性)
{
var propertyType=Nullable.GetUnderlyingType(property.propertyType)??property.propertyType;
if(propertyType.Namespace==“系统”)
{
var value=property.GetValue(eObject);
SetValue(returnObject,value);
}
}
返回对象;
}
返回eObject;
}
您为什么要这样做,您想实现什么?EF代理从实际实体继承,那么回溯到原始类型会给您带来什么呢?例如,Ben会重载方法来处理一些实体类型。对于代理,它不适用于这样的内容checkRequired(客户c)
,checkRequired(订单o)
我更正了我的评论。如果我们有checkRequired(objecto)
(我的案例),它将被调用,而不是因为代理而调用其他重载。但是如果对象o
的重载不存在,它将调用相关的方法(接受客户、订单等的方法)。不完美,但至少有用。如果上下文用于其他线程,则另一个答案可能会绊倒您。。。只是一个警告。另外,您必须处理一个被跟踪的实体,因此不能是.AsNoTracking()查询的结果。@IDisposable在多个线程中使用上下文是不健康的。是的,它必须是一个被跟踪的实体。如果有一个链接实体也是代理类型的,那么情况如何?i、 e.具有员工类型代理实体关系列表的代理实体公司。您的函数只是将任何关系转换为null。@DFTR这就是所要求的。要填充导航属性,应内置递归循环。请放心:)我现在碰巧看到了这一点,但我不知道这是如何回答这个问题的context.ChangeTracker.Entries()
不返回基类型,而是返回代理。延迟执行是关于什么的?至于批评,我的方法没有重新加载任何内容。唯一的一点是不保留未映射的属性。更改了我的答案以明确延迟执行。嗯,我可能错误地从DB中重新加载数据。显然,我将其与原始值(我在应用程序中碰巧需要这些值)混淆了。Ajay的解决方案仍然是唯一好的解决方案:使用ObjectContext.GetObjectType()。这是一个静态方法,因此您实际上不需要对DbContext的引用。@codetuner如果您的项目中没有对Entity Framework的引用,那么您将根本无法访问DbContext,这是我的情况。@codetuner同样,我的API需要传递一个object
类型的变量。所以我