已经有一个打开的 DataReader 与此命令关联,必须先关闭它 - Foreach 循环 if 语句

There is already an open DataReader associated with this Command which must be closed first - Foreach loop if statement

我正在尝试遍历危害列表,以查看是否已在 ControlMeasures 中为每种危害添加了控制措施。 如果每个危害都有控制措施,那么我将 complete 设置为 true,如果没有,我将打破 foreach 循环,将 complete set 设置为 false。

我在下面编写了 foreach 循环,但在运行时,我收到以下针对 if 条件语句的错误:

There is already an open DataReader associated with this Command which must be closed first.

我做了一些研究,看起来我没有以正确的方式编写代码,但由于我对此还是新手,所以我无法找到更好、更正确的编写方式。

[HttpGet]
    public ViewResult AddControlMeasure(int raId)
    {
        // Get list of hazardids for this RA  
        IEnumerable<int> hazardIds = db.RiskAssessmentHazards.Where(x => x.RiskAssessmentId == raId).Select(x => x.HazardId);

        var complete = false;
        foreach (int HazardsId in hazardIds)
        {
            if (db.ControlMeasures.Where(x => x.HazardId == HazardsId && x.RiskAssessmentId == raId).Count() == 0)
            {
                break;
            }
            else
            {
                complete = true;
            }
        }

这一行:

IEnumerable<int> hazardIds = db.RiskAssessmentHazards
    .Where(x => x.RiskAssessmentId == raId).Select(x => x.HazardId);

Returns 一个惰性计算序列(实际上是一个 IQueryable,在您开始枚举之前不会访问数据库(foreach)。

循环:

foreach (int HazardsId in hazardIds)
{
    ...
}

将打开与数据库的连接,获取 reader,并且对于每次迭代,沿着 reader 移动以获取数据。这意味着连接在循环期间具有活动的 reader。

最后,这一行:

if (db.ControlMeasures.Where(x => x.HazardId == HazardsId && x.RiskAssessmentId == raId).Count() == 0)

尝试使用连接(与您的db关联)执行另一个查询。由于 foreach 循环可查询,您已经有一个活动的 reader,这会引入您收到的错误。

尽管在循环中执行查询通常不是一个好主意,但最简单的解决方案是使用 .ToArray() 或其他一些方式在迭代循环之前完全实现结果:

int[] hazardIds = db.RiskAssessmentHazards
    .Where(x => x.RiskAssessmentId == raId)
    .Select(x => x.HazardId)
    .ToArray();

这样 reader 将在您开始迭代循环并执行后续查询之前关闭。

Where, Select,GroupByOrderBy 等方法使用延迟执行(这会导致像您的情况一样打开 DataReader)。这些方法不强制执行查询,因此查询执行被推迟到枚举之前。因此,您应该自己使用 ToList()ToArray().

进行枚举

在您的情况下,您应该强制枚举“hazardIds”,例如

IEnumerable<int> hazardIds = db.RiskAssessmentHazards
                            .Where(x => x.RiskAssessmentId == raId)
                            .Select(x => x.HazardId).ToArray();