2015-11-04 83 views
1

我想通过一系列危险来查看是否已在ControlMeasures中为每个危险添加了控制措施。 如果每个危险都有一个控制措施,那么我将complete设置为true,否则我会中断foreach循环,将complete set设置为false。已经有一个打开的DataReader与此命令相关联,必须先关闭 - Foreach循环,如果语句

我已经写了下面的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; 
      } 
     } 
+0

我认为你需要添加一个'.ToList'或'.ToArray'你'hazardIds'选择的结尾,否则在完成整个枚举之前,不会关闭该读者的连接。我也确信有一种方法可以在没有for循环的情况下进行,但我现在正在画一个空白。 –

+0

可能是因为'db.RiskAssessmentHazards'返回'IQueryable',所以在执行foreach循环时并没有真正执行。 – markpsmith

回答

3

这条线:

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

返回一个懒惰的评估程序(真正的IQueryable,直到你开始枚举(该foreach)不会打数据库

循环:

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

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

最后,这条线:

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(); 

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

+0

非常感谢您的一个很好的答案,我很好的学习了很多,并修复了问题 –

2

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

在你的情况,你应该强制枚举`hazardIds'像

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

@BasharAbuShamaa没有问题。很高兴它有帮助。) – user2771704

相关问题