已经有一个打开的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;
}
}
此行:
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,GroupBy
和OrderBy
这样的方法使用延迟执行(这会导致像您的情况一样打开DataReader)。这些方法不会强制执行查询,因此查询的执行将推迟到枚举。因此,您应该使用ToList()
或ToArray()
自己进行枚举。
在您的情况下,您应该强制枚举像这样的"hazardId"
IEnumerable<int> hazardIds = db.RiskAssessmentHazards
.Where(x => x.RiskAssessmentId == raId)
.Select(x => x.HazardId).ToArray();