C# Linq调用-已经有一个与此命令关联的打开的DataReader,必须先关闭它

C# Linq调用-已经有一个与此命令关联的打开的DataReader,必须先关闭它,c#,linq,C#,Linq,我有一些代码,当运行“EntityCommandExecutionException”类型的异常时会引发 Visual Studio指向的线: else if (item.FirstOrDefault().InspectionEquipmentTypes.Any()) 例外情况的内部细节说明: There is already an open DataReader associated with this Command which must be closed first. 我的问题是引发

我有一些代码,当运行“EntityCommandExecutionException”类型的异常时会引发

Visual Studio指向的线:

else if (item.FirstOrDefault().InspectionEquipmentTypes.Any())
例外情况的内部细节说明:

There is already an open DataReader associated with this Command which must be closed first.
我的问题是引发错误的那一行没有尝试使用数据库/数据读取器(据我所知),因此我不确定为什么会生成此异常

编辑:


当您以嵌套方式进行查询时,就会发生这种情况

item.FirstOrDefault().InspectionEquipmentTypes.ToList().Any()
可能有用。不过我不确定。尝试简化嵌套查询。例如,不要进行如下查询:

items.Where(/*some condition*/).Any();
取而代之的是制造

items.Any(/*some condition*/);

如果您真的想要嵌套查询(我不建议这样做,我宁愿使用一些散列数据结构进行单独的查询和链接实体),并且您使用的是sql server,那么您实际上有一个替代方案:激活MARS。要激活它,只需添加连接字符串MultipleActiveResultSets=True。有关更多详细信息,请访问此链接:

下面是发生的情况:当您循环执行
批检查时,数据库读取器正在从数据库中读取此集合。在循环中,通过大量的
First(OrDefault)
调用、
Sum
Count
执行新的数据库读取。这会导致异常“已存在打开的DataReader…”

正如George Lica所说,您可以通过在连接字符串中设置
MultipleActiveResultSets=True
来解决这个问题

或者,您可以在循环开始创建之前,通过以下方式完成对批处理检查的读取:
batchInspections

foreach (var item in batchInspections.ToList())
但是,首先收集您需要的数据,然后循环使用,效率要高得多:

foreach (var item in batchInspections
            .Select(b => new 
                         {
                             First = b.FirstOrDefault(),
                             Count = b.Count(),
                             Sum = b.Sum(s => s.Duration)
                         } )
            .ToList())
{
    var bigi = new BatchInspectionGridItem();
    if (item.Any())
    {
        bigi.BatchInspectionNo = item.First.InspectionBatchNo;

        if (item.First.EquipmentTypeID != null)
        {
            bigi.EquipmentTypeName = item.First.EquipmentType.Description;
        }
        else if (item.First.InspectionEquipmentTypes.Any())
        {
            bigi.EquipmentTypeName = string.Join(" / ", item.First.InspectionEquipmentTypes.Select(s => s.EquipmentType.Description));
        }
        bigi.CustomerName = item.First.CustomerSite.Customer.CustomerName;
        bigi.CustomerID = item.First.CustomerSite.Customer.CustomerID;
        bigi.NumberOfInspections = item.Count;
        bigi.TotalDuration = item.Sum;
    }

    viewModel.BatchInspectionGridViewModel.Add(bigi);
}
我希望
SchedulerManager.GetUnscheduledBatchInspections
返回一个
IQueryable
,以便后续的
Select
匿名类型将被转换为SQL


必须指出的是,激活MARS对于实体框架来说几乎总是一个好主意,因为延迟加载会导致这种异常。

您可以发布更多的代码来显示
是如何创建的吗?您在条件表达式中使用了LINQ。可以想象,以前的条件表达式将上下文绑定起来进行类似的检查。我猜您使用的是LINQtoSQL或LINQtoEntity框架。无论采用哪种方式,您都可以设置到数据库的连接,以允许多个活动结果集同时使用多个数据读取器。只需在连接字符串中添加以下内容:MultipleActiveResultSets=true;你能解释一下为什么是items.Where(“条件”).Any();比项目更糟糕。有任何(“条件”)?我猜.Any()只检查结果集,不运行额外的查询?虽然确实有技术上的好处,但我并不完全了解它们,但是增加可读性就足够了。
foreach (var item in batchInspections.ToList())
foreach (var item in batchInspections
            .Select(b => new 
                         {
                             First = b.FirstOrDefault(),
                             Count = b.Count(),
                             Sum = b.Sum(s => s.Duration)
                         } )
            .ToList())
{
    var bigi = new BatchInspectionGridItem();
    if (item.Any())
    {
        bigi.BatchInspectionNo = item.First.InspectionBatchNo;

        if (item.First.EquipmentTypeID != null)
        {
            bigi.EquipmentTypeName = item.First.EquipmentType.Description;
        }
        else if (item.First.InspectionEquipmentTypes.Any())
        {
            bigi.EquipmentTypeName = string.Join(" / ", item.First.InspectionEquipmentTypes.Select(s => s.EquipmentType.Description));
        }
        bigi.CustomerName = item.First.CustomerSite.Customer.CustomerName;
        bigi.CustomerID = item.First.CustomerSite.Customer.CustomerID;
        bigi.NumberOfInspections = item.Count;
        bigi.TotalDuration = item.Sum;
    }

    viewModel.BatchInspectionGridViewModel.Add(bigi);
}