为什么EF返回的是代理类而不是实际实体

本文关键字:实体 代理 EF 返回 为什么 | 更新日期: 2023-09-27 18:26:23

当我想要实际的实体类时,实体框架返回Proxies时遇到了问题。第一次运行代码时,一切都正常运行(没有代理),但之后的每次迭代,我的一个DbSet总是返回代理,而不是实际类型。

我在每次迭代后都会处理上下文,所以我不明白为什么第一次迭代有效,而之后的每次都无效。

我的代码在这一行失败了。我的所有POCO都设置了Table属性,但因为它返回了一个代理类,所以没有表属性。

TableAttribute attrib = (TableAttribute)attributes.Single();

在我销毁对象后,DbContext中是否存在一些幕后静态魔法?

我使用以下将我的对象移动到内存中

MajorClasses = ctx.MajorClasses.ToArray();

我也试过

MajorClasses = ctx.MajorClasses.AsNoTracking().ToArray();

在我的OnModelCreating中,我有以下设置

base.Configuration.ProxyCreationEnabled = false;
            base.Configuration.LazyLoadingEnabled = false;

为什么EF返回的是代理类而不是实际实体

您可以将ObjectContext.ContextOptions.ProxyCreationEnabled设置为false。这将阻止您使用EF的一些奇特功能,如延迟加载和我相信的更改跟踪。

就你的应用程序而言,它应该能够像对待代理所代表的类型一样对待代理。你有什么特别的问题吗?

编辑

我们有一些代码需要POCO类型而不是代理类型,我们执行以下操作来检测当前类型是否为代理。

if (entityType.BaseType != null && entityType.Namespace == "System.Data.Entity.DynamicProxies")
{
    entityType = entityType.BaseType;
}

要关闭实体框架5中的代理创建,您可以使用以下

_dbContext.Configuration.ProxyCreationEnabled = false;

在使用上下文提取数据之前,只需设置一次此属性。

默认情况下,EF使用更改跟踪并使用所有实体的内存缓存。使用EF时,可以使用不同的"合并选项"。默认情况下,EF 4.1设置为AppendOnly Merge Option。据我所知,这意味着如果您已经查询了一个实体,那么后续查询将从缓存中获取该实体(如果数据库中没有检测到更改)。因此,您可能会看到缓存的实体正在返回。

在EF 4.1中,您可以使用NoTracking Merge Option。这将转到每个调用的数据库中。

在EF 6.1.3中,您可以使用获得正确的类型

using (var context = new BloggingContext()) { 
    var blog = context.Blogs.Find(1); 
    var entityType = ObjectContext.GetObjectType(blog.GetType()); 
}

请注意,如果传递给GetObjectType的类型是不是代理类型的实体类型的实例,则仍会返回实体类型。这意味着您可以始终使用此方法来获取实际的实体类型,而无需进行任何其他检查来查看该类型是否为代理类型。

来自MSDN

简单的解决方案是,您缺少一些必须包含的对象,并且在获取值之前也要执行此操作

_dbContext.Configuration.ProxyCreationEnabled = false;

在我的案例中,通过将Lazy Loading Enabled设置为false解决了此问题。

  1. 打开.edmx(图表)
  2. 按F4调出属性
  3. Lazy Loading Enabled设置为false
  4. 保存并重新生成