实体框架使用IQueryable打开DataReader .Include(IQueryable,String)

时间:2016-08-01 21:56:41

标签: c# entity-framework

编辑:原始文件假定错误发生在特定的地方,但似乎不是。我很感激有关如何追踪数据阅读器打开位置的任何建议 - 通过EF追踪它的一些方法是理想的,因为我还没有找到任何有效的方法。

我遇到了Entity Framework的问题,这给我带来了开放的数据读取错误,我不确定原因。

背景

我为我的应用程序的中间层实现了一个通用基础存储库类。旧版本使用返回基类的通用“FindAll()”方法,然后我们依靠延迟加载来填充业务逻辑中的关系。由于这不如预期加载那么好,我们添加了一堆“FindByEager”方法,这些方法直接访问DbSet并使用.Include(t => t.propertyName)来获取稍后需要的预先加载属性。

问题

this article的启发(参见“创建通用存储库”标题下),作为更大的重构的一部分,我正在尝试实现一个更通用的“FindAll”方法,该方法可以使用动态添加包含方法DbExtensions.Include(IQueryable, String)。我的基础存储库中生成的代码如下所示:

    public virtual IQueryable<T> FindAll(string includeProperties = "")
    {
        var query = NcContext.Set<T>().AsQueryable();

        foreach (var property in includeProperties.Split
            (new char[] {','}, StringSplitOptions.RemoveEmptyEntries))
        {
            query = query.Include(property);
        }

        return query;
    }

然而,实体框架并不喜欢这个。当我尝试迭代包含属性字符串和.Include每个属性时,EF希望将其视为对打开的DataReader的操作(旧的错误“已经存在与此连接关联的打开的DataReader,必须首先关闭“每当我们尝试执行结果查询时出现。”

为什么我认为这是问题

  • 我尝试过跟踪堆栈跟踪并修改其他一些方法,以确保我之前使用的每个连接都使用.ToList()执行。我看不到其他地方可能有数​​据阅读器打开。

  • 我正在调试器中逐步执行此方法。传递var query = ...行后,我可以成功枚举查询并获得结果。一旦我走过.Include()之一(即通过foreach循环),如果我尝试枚举查询,我就会遇到问题。

我有兴趣了解为什么会发生这种情况(没有找到很多关于此的文档的运气)以及如何解决它。它也打破了我对Entity如何工作的理解,因为它不应该延迟执行构建的查询直到实际的评估时间?

我还没有尝试的可能解决方案:

  • 传递表达式而不是字符串&amp;使用其他DbExtensions.Include<T, TProperty> (IQueryable<T>, Expression<Func<T, TProperty>>)重载。无论这是否是解决方案,我想了解为什么实体会产生这种行为。

  • 使用.ToList()将DbSet拉入内存。我试图允许消费类至少有一点可重用性来微调他们正在运行的查询,所以我想返回一个Queryable,并强制执行查询然后重新转换为Queryable似乎不效率很高。

无论这些是否会修复它(如果它们会更新),我会有兴趣知道我在这里做错了什么以及它为什么会这样。

感谢您的帮助。

0 个答案:

没有答案