2015-07-24 3 views
0

У меня есть код, который при запуске исключает тип «EntityCommandExecutionException».Linq Call - есть уже открытый DataReader, связанный с этой командой, который должен быть закрыт первым

Линия, Визуальные точки Студийные к:

else if (item.FirstOrDefault().InspectionEquipmentTypes.Any()) 

внутренней детали, за исключением сказать, что:

There is already an open DataReader associated with this Command which must be closed first. 

Мой вопрос линия, которая подняла ошибку, не пытается использовать database/datareader (насколько мне известно), поэтому я не уверен, почему генерируется это исключение.

Edit:

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); 
     } 
    } 
+1

Можете ли вы опубликовать еще один код, чтобы показать определение того, как создается «элемент»? –

+0

Вы используете LINQ внутри условного выражения. Можно предположить, что предыдущие условные выражения имеют контекст, связанный с аналогичными проверками. –

+0

Я предполагаю, что вы используете linq для sql или linq для сущности. В любом случае вы можете настроить соединение с dbase, чтобы разрешить несколько активных наборов результатов, которые позволяют вам одновременно использовать несколько DataReaders. Просто добавьте в строку подключения следующее: MultipleActiveResultSets = true; –

ответ

2

Вот что происходит: пока вы проходите через batchInspections, читатель базы данных читает эту коллекцию из базы данных. Внутри цикла вы читаете новые базы данных многочисленными звонками First(OrDefault), Sum и Count. Это вызывает исключение «Существует уже открытый DataReader ...».

Как сказал Джордж Лика, вы можете решить эту проблему, установив MultipleActiveResultSets=True в строку подключения.

Или вы можете закончить чтение batchInspections перед цикл начинается itereating по ...

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 в анонимный тип будет переведен в S QL.

Следует сказать, что активизация MARS почти всегда является хорошей идеей с Entity Framework, поскольку ленивая загрузка имеет способ вызвать это исключение.

0

Это происходит, когда вы делаете запросы в гнездовой образом.

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

может работать. Хотя я не уверен. Попробуйте упростить вложенные запросы. Например, не делают запросы, как:

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

вместо сделать

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

Можете ли вы объяснить, почему items.Where ("condition"). Any(); хуже, чем items.Any ("condition")? Я предполагаю. Любой() просто проверяет набор результатов и не запускает дополнительные запросы? – andrewb

+0

Несмотря на то, что есть технические преимущества, я не полностью признал их, но для повышения удобочитаемости было бы достаточно причин. –

0

Если вы действительно хотите иметь вложенные запросы (я не рекомендую, я предпочел бы сделать отдельные запросы и ссылку объекты используя некоторые хеширующие структуры данных), и вы используете сервер sql, у вас есть альтернатива: активируйте MARS. Чтобы активировать его, просто добавьте в строку подключения MultipleActiveResultSets = True. Для получения более подробной информации перейдите по этой ссылке: https://msdn.microsoft.com/en-us/library/h32h3abf(v=vs.110).aspx