Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/339.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 从实体框架代理获取基础实体对象_C#_Entity Framework - Fatal编程技术网

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
类型的变量。所以我