2012-04-06 3 views
1

В моем приложении я искал странную ошибку. Он поступает по уровням или сообщениям об ошибках:Linq 2 Sql - Уже открыт datareader Выпуск

  1. Имеются уже и открыты данные, связанные с данными. Затем приходит
  2. Неверная попытка вызова Чтение, когда читатель закрыт. Далее
  3. Индекс находился за пределами массива. Затем наступает
  4. Указанный приказ недействителен.

Позвольте мне сначала объяснить, что делает мой код: Я использую шаблон репозитория для своего приложения Linq-Sql. Из этого хранилища звоню этот метод

internal static IEnumerable<ParentChild> GetAllCategoriesAndSubcategories() 
     { 
      lock (Context) // lock is implemented just before asking question, to check whether it can solve the issue or not... 
      { 
       return from p in Context.Categories 
         let relatedchilds = (from c in Context.SubCategories 
              where c.CategoryId == p.Id 
              select c).Take(5) 
         select new ParentChild 
         { 
          Parent = p, 
          Childs = relatedchilds 
         }; 
      } 

     } 

Этот метод выбора строк из двух таблиц, Родитель и ребенок, и возвращает результат в виде новой коллекции класса

public class ParentChild 
    { 
     public Category Parent { get; set; } 
     public IEnumerable<SubCategory> Childs { get; set; } 
    } 

Иногда он работает отлично но когда увеличение трафика и параллелизм, тогда в этом случае я начну получать эти ошибки. Исходя из этого вопроса, из пользовательского интерфейса я потребляю IEnumerable<ParentChild> GetAllCategoriesAndSubcategories(), чтобы отобразить его в иерархии.

В пользовательском интерфейсе я использую этот метод для визуализации текста:

/// <summary> 
     /// Write categories Jquery html to the Category usercontrol 
     /// </summary> 
     private void WriteCategories() 
     { 

      // retrieves all categories and its subcategories as a generic list of ParentChild 
      var dt = CategoryRepository.GetAllCategoriesAndSubcategories(); 

      //Conversion of dynamic jquery html string starts here 
      var sb = new StringBuilder(); 
      sb.AppendLine(" <div class='widget_box' id='category'>"); 
      sb.AppendLine("  <div class='wintitle'>"); 
      sb.AppendLine("   <div class='inner_wintitle'>Categories</div>"); 
      sb.AppendLine("  </div>"); 
      sb.AppendLine("  <div class='winbody'>"); 
      sb.AppendLine("   <ul class='categories'>"); 
      var i = 1; 
      foreach (ParentChild item in dt) //<--* BUGGY PART* 
      { 
       sb.AppendLine(
        string.Format("<li class='catetitle' id='catetitle{0}'><a href='subcategory.aspx?cid={1}&cname={2}'>{2}</a></li>", i, 
            item.Parent.Id, item.Parent.Name)); 
       sb.AppendLine(
        string.Format("<li style='display:none;' class='category_sub' id='subcategory{0}' ><div><ul>", i)); 
       foreach (var subCategory in item.Childs) 
       { 
        sb.AppendLine(string.Format("<li><a href='subcategory.aspx?cid={0}&cname={1}&scid={2}&scname={3}'>{3}</a></li>", item.Parent.Id, 
               item.Parent.Name, subCategory.Id, subCategory.Name)); 
       } 
       sb.AppendLine(
        string.Format(
         "<li class='catetitle' id='catetitle{0}'><a href='subcategory.aspx?cid={1}&cname={2}'>View all categories</a></li>", 
         i, item.Parent.Id, item.Parent.Name)); 
       sb.AppendLine("</ul></div></li>"); 
       i++; 
      } 
      sb.AppendLine("</div></ul></div>"); 
      //Conversion of dynamic jquery html string ends here 

      // javascript function to display the subcategories when mouse is hovered to the category 
      sb.AppendLine("<script type='text/javascript'>init_categories();</script>"); 
      ucCategories1.CategoryHtml = sb.ToString(); // Generated text is finally set to the usercontrols property. 
     } 

Я получаю ошибку @foreach (ParentChild item in dt). Пожалуйста, помогите мне.

Предложение Требуется: Я использую это как мой реализации шаблона репо:

internal sealed class LeadsRepository : IRepository<BuySell> 
    { 
     private static readonly BusinessBazaarDataContext Context; 

     static LeadsRepository() 
     { 
      Context = new BusinessBazaarDataContext(); 
     } 
} 

не считает это хороший способ использовать DataContext. Пожалуйста, предложите мне ... Спасибо

+0

Я передал 'DataContext' в' LeadsRepository' через инсталляцию конструктора. [Мне не нравится статика.] (Https://sites.google.com/site/steveyegge2/singleton-considered-stupid). Вы можете использовать инфраструктуру инверсии управления (IoC) (например, Ninject, StructureMap, Windsor Castle) для решения проблем, связанных с жизнью. –

ответ

1

Переключитесь на List<ParentChild> и верните полностью заполненный List с GetAllCategoriesAndSubcategories. Ваш lock будет делать то, что вы намерены (так я предполагаю).

В частности, вам нужно сделать:

internal static IList<ParentChild> GetAllCategoriesAndSubcategories() 
    { 
     lock (Context) // lock is implemented just before asking question, to check whether it can solve the issue or not... 
     { 
      return (from p in Context.Categories 
        let relatedchilds = (from c in Context.SubCategories 
             where c.CategoryId == p.Id 
             select c).Take(5) 
        select new ParentChild 
        { 
         Parent = p, 
         Childs = relatedchilds 
        }).ToList(); 
     } 

    } 
+0

Спасибо, позвольте мне попробовать ... –

+0

еще один запрос .. см. Мой обновленный вопрос. Я использую это как реализацию шаблона репозитория. Это правильный способ ..... Предложите мне хороший ресурс, чтобы использовать преимущества L2S и Repo Pattern –

1

Есть две проблемы в вашем коде.

Непосредственной причиной ошибки является один идентификатор Бретта Венеры. Без вызова ToList() вы возвращаете запрос (типа IQueryable). Запрос не будет выполняться до тех пор, пока он не будет пронумерован (то есть зациклирован). Вы не делаете этого в своем блоке lock, вместо этого он выполняется всякий раз, когда используется результат.

Средство Бретта к этому относится правильно. Вызов ToList() по запросу запустит запрос и сохранит результаты в списке в памяти в пределах блок using. Вам нужно добавить еще один ToList() запрос, хотя, в оператор realtedChilds. В противном случае у вас будет такая же проблема.

Другая проблема заключается в том, что вы используете один контекст данных между потоками. Контекст данных никогда не был предназначен для этого. Вместо этого контекст данных предназначен для работы . Создать один, когда вам это нужно, и избавиться от него быстро:

using(context = new MyDataContextClass()) 
{ 
    return (from p in Context.Categories 
      let relatedchilds = (from c in Context.SubCategories 
           where c.CategoryId == p.Id 
           select c).Take(5).ToList() 
      select new ParentChild 
      { 
      Parent = p, 
      Childs = relatedchilds 
      }).ToList(); 
} 

В вашем случае, когда вы завернутые контекст данных в хранилище, может иметь смысл, чтобы хранилище будет единица работы и иметь контекст как член в репозитории. Это означает, что ваш репозиторий будет реализовывать IDisposable и удалять контекст данных элемента в методе Dispose().

В качестве побочного примечания есть еще одна проблема с вашим кодом. Он будет выполнен в два этапа. Сначала он получит всех родителей, затем для каждого родителя он снова попадет в базу данных с просьбой предоставить своим детям. С более чем несколькими 10 родителями это будет проблемой производительности.

Правильный способ сделать это в linq-to-sql - это запросить всех детей, выполнив ToList(), а затем linq-to-objects GroupBy(). Некоторое время назад я написал об этом blog entry.

+0

еще один запрос .. см. Мой обновленный вопрос. Я использую это как реализацию шаблона репозитория. Это правильный способ ..... Предложите мне хороший ресурс для использования преимуществ L2S и Repo Pattern –

+1

Если у вас есть другой вопрос, пожалуйста, разместите новый вопрос, а не добавьте его в текущий. Мой 2c-редизайн linq-to-sql и репозиторий - это то, что linq-to-sql * - это * репозиторий. Я не вижу смысла обертывать его в еще один репозиторий. –

+0

Можете ли вы предоставить мне хорошие ссылки или ссылку для L2S .... Спасибо –

1

Да, согласен с ToList

Причина:

"IEnumerable" выполняет все операции в C# код, т.е. LINQ-к-объектов. Это означает, что все действия будут выполняться в C#, следовательно, это связано с природой

Как только вы вызываете данные с помощью IEnumerable, все данные будут извлекаться из базы данных и отправляться в .net. Это может резко ухудшить производительность (например, индексы базы данных не будут использоваться linq-to-objects), но, с другой стороны, linq-to-objects более гибкие, поскольку он может выполнять произвольный код C#, а не ограничиваться тем, что ваш провайдер linq может перевести на SQL.

+0

На самом деле, я использую Resharper для очистки кода и рефакторинга и т. Д. Поэтому я использую IList или List в качестве типа возврата, он предлагает мне использовать IEnumerable вместо , Обычно я возвращаю IList для привязки цели. –

+0

Ahan, это решило вашу проблему? – nalaiqChughtai

+0

Как я уже сказал, это происходит очень редко или без колебаний, поэтому я не могу сказать, что его решение разрешено или нет. Но я думаю, я должен принять ответ ... еще один запрос .. см. Мой обновленный вопрос. Я использую это как реализацию шаблона репозитория. Правильно ли это ... Предложите мне хороший ресурс для использования преимуществ L2S и Repo Pattern –

Смежные вопросы