从实体框架代理获取底层实体对象

时间:2014-09-10 16:16:42

标签: c# entity-framework

我从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

6 个答案:

答案 0 :(得分:41)

使用EF 6时,我使用以下代码从代理类型中获取基础POCO实体类型,

var entityType = ObjectContext.GetObjectType(dbEntitymodifiedEntry.Entity.GetType());

ObjectContext.GetObjectType:从代理对象

返回POCO

参考: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;
}
相关问题