已经有一个打开的 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,GroupBy
和 OrderBy
等方法使用延迟执行(这会导致像您的情况一样打开 DataReader)。这些方法不强制执行查询,因此查询执行被推迟到枚举之前。因此,您应该自己使用 ToList()
或 ToArray()
.
进行枚举
在您的情况下,您应该强制枚举“hazardIds”,例如
IEnumerable<int> hazardIds = db.RiskAssessmentHazards
.Where(x => x.RiskAssessmentId == raId)
.Select(x => x.HazardId).ToArray();
我正在尝试遍历危害列表,以查看是否已在 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,GroupBy
和 OrderBy
等方法使用延迟执行(这会导致像您的情况一样打开 DataReader)。这些方法不强制执行查询,因此查询执行被推迟到枚举之前。因此,您应该自己使用 ToList()
或 ToArray()
.
在您的情况下,您应该强制枚举“hazardIds”,例如
IEnumerable<int> hazardIds = db.RiskAssessmentHazards
.Where(x => x.RiskAssessmentId == raId)
.Select(x => x.HazardId).ToArray();