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

时间:2015-07-24 14:00:31

标签: 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.

我的问题是提出错误的行不是尝试使用数据库/ datareader(据我所知)所以我不确定为什么会生成此异常。

编辑:

    public static IEnumerable<IGrouping<string,Entities.Inspection>> GetUnscheduledBatchInspections(Entities.EntityModel context)
    {
        var results = context.Inspections.Where(w =>
            w.InspectionBatchNo != null
            && w.IsCancelled == false
            && !w.CalendarItems.Any()
            && w.Duration.HasValue).GroupBy(g => g.InspectionBatchNo);
        return results;
    }

通话方式:

    private void MapBatchInspectionsToViewModel(ref SchedulerViewModel viewModel)
    {
        var batchInspections = SchedulerManager.GetUnscheduledBatchInspections(this.Context);

        foreach (var item in batchInspections)
        {
            var bigi = new BatchInspectionGridItem();
            if (item.Any())
            {
                bigi.BatchInspectionNo = item.First().InspectionBatchNo;

                if (item.FirstOrDefault().EquipmentTypeID != null)
                {
                    bigi.EquipmentTypeName = item.FirstOrDefault().EquipmentType.Description;
                }
                else if (item.FirstOrDefault().InspectionEquipmentTypes.Any())
                {
                    bigi.EquipmentTypeName = string.Join(" / ", item.FirstOrDefault().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(s => s.Duration);
            }

            viewModel.BatchInspectionGridViewModel.Add(bigi);
        }
    }

3 个答案:

答案 0 :(得分:2)

以下是发生的事情:当您遍历batchInspections时,数据库读取器正在从数据库中读取此集合。在循环中,您通过众多First(OrDefault)调用SumCount进行新的数据库读取。这导致异常'已经有一个开放的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。

必须要说的是,使用Entity Framework激活MARS几乎总是一个好主意,因为延迟加载有一种导致此异常的方法。

答案 1 :(得分:0)

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

item.FirstOrDefault().InspectionEquipmentTypes.ToList().Any()

可能会奏效。我不确定。尝试简化嵌套查询。例如,不要进行如下查询:

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

而不是

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

答案 2 :(得分:0)

如果你真的想要嵌套查询(我不建议这样做,我宁愿使用一些散列数据结构进行单独的查询和链接实体)并且你使用的是sql server,你实际上有另一种选择:activate火星。要激活它,只需添加连接字符串MultipleActiveResultSets = True。有关详细信息,请访问以下链接:https://msdn.microsoft.com/en-us/library/h32h3abf(v=vs.110).aspx