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

本文关键字:语句 if 循环 -Foreach 关联 有一个 DataReader 命令 | 更新日期: 2023-09-27 18:20:35

我正试图循环浏览危险列表,看看是否在控制措施中为每个危险添加了控制措施。如果每个危险都有一个控制度量,那么我将complete设置为true,如果不是,我将打破foreach循环,将complete设为false。

我已经在下面编写了foreach循环,但在运行时,我在if条件语句中显示了以下错误:

已经有一个打开的DataReader与此命令关联,必须先关闭它。

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

[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;
            }
        }

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

此行:

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

返回一个延迟求值序列(实际上是一个IQueryable,在您开始枚举(foreach)之前,它不会进入数据库。

循环:

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

将打开与数据库的连接,获取读取器,并在每次迭代中沿着读取器移动以获取数据。这意味着连接在循环期间有一个活动的读取器。

最后,这一行:

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

尝试使用连接(与db关联)执行另一个查询。由于foreach循环的可查询性,您已经有了一个活动的读卡器,这将导致您收到的错误。

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

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

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

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

在您的情况下,您应该强制枚举像这样的"hazardId"

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