Entity Framework:这个命令已经关联了一个必须先关闭的开放式DataReader。

10

这个问题与这个有关:

我的仓储方法中有这段代码:

 public IEnumerable<ApplicationPositionHistory> GetApplicationPositionHistories(int applicantId, int positionId)
        {
            return context.ApplicationsPositionHistory.Where(d => d.applicantPosition.ApplicantID == applicantId && d.applicantPosition.PositionID == positionId).Include(o => o.applicantPosition) ;
        }

我的 HTML 代码如下:

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.applicantPosition.Applicant.name)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.applicantPosition.Position.name)
        </td>

完整的异常信息如下:

此命令已经关联了一个必须先关闭的打开的DataReader。

该异常是在HTML的第一行抛出的 @Html.DisplayFor(modelItem => item.applicantPosition.Applicant.name)

5个回答

24

快速解决方案:

public IEnumerable<ApplicationPositionHistory> GetApplicationPositionHistories(int applicantId, int positionId)
    {
        return context.ApplicationsPositionHistory.Where(d => d.applicantPosition.ApplicantID == applicantId && d.applicantPosition.PositionID == positionId).Include(o => o.applicantPosition).ToList() ;
    }
如果你想知道为什么这个修复可以解决你的问题,请了解一下LINQ和“延迟执行”的工作原理。简单来说,如果你不通过将查询强制转换为ToList并对其进行枚举来“强制”执行选择操作,则实际上会在视图中过晚地执行该操作。这会导致其他想要使用同一连接的查询出现问题。

当我重新实现两个类似的模型类以继承使用TPH继承结构的模型基类时,我遇到了同样的错误,其中一个派生类有一个一对零或一的关系,并且我在控制器中为该模型使用急切加载。据我所知,在这种情况下不支持急切加载,因此在控制器中删除此属性的.Include(...),并在我的剩余.Include(...)语句的末尾添加.ToList()似乎已经解决了问题-谢谢。 - Aaron Newton

12

你尝试过在连接字符串中添加MultipleActiveResultSets=true;吗?


2
我之前使用了 context.<DbSet>.Find(id) 这个方法,但不知何故导致了 OP 提到的错误。将这个设置添加到连接字符串中解决了这个问题。 - user191152

6
当你在执行一个查询时,如果又要执行一个新的查询,就会出现这个错误。考虑你的视图中有类似以下内容:
@Html.DisplayFor(modelItem => item.Device.Name)

在您的设备型号中,您拥有

    public string Name
    {
        get
        {
            return String.Format("{0} {1}", Brand.BrandName, Model.ModelName);
        }
    }

由于评估Device.Name需要查询其品牌和型号,因此它将成为嵌套查询。解决方案是在数据库连接字符串中启用MutlipleActiveResultSets

    <add name="MyDBContext" connectionString="Data Source=.;Initial Catalog=mydb;Integrated Security=True;MultipleActiveResultSets=True" providerName="System.Data.SqlClient" />

3

通常不要在视图中使用EF对象,而是为视图模型创建POCO对象,并将查询结果映射到视图模型上。EF不会在存储库方法中执行查询,因为这些查询不是在定义时执行的,而是仅在尝试访问数据时才执行。在视图中多次使用相同的查询是不正确的。

如果您想访问由存储库方法返回的对象列表,请使用toList


1

真正的问题是在查询结束之前,你从申请职位实体中懒加载了位置引用。如果您想在这种情况下保持延迟执行,可以像下面这样急切地加载查询中的位置引用:

Include(o => o.applicantPosition.Select(a => a.Position));

并且在GetApplicationPositionHistories方法中继续返回IEnumerable。

另一种解决方案是在GetApplicationPositionHistories方法上运行查询,并在查询上调用ToList()或ToArrray()方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接