2012-04-06 65 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; } 
    } 

有時它工作正常,但是當採摘行流量增加和併發性,那麼在這種情況下,我開始得到這些錯誤。來到這個問題,從UI我消耗IEnumerable<ParentChild> GetAllCategoriesAndSubcategories()顯示它在heirarchy。

在UI我使用這種方法來渲染文本:

/// <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 )來處理終身關切。 – 2012-04-13 14:19:41

回答

1

切換到List<ParentChild>並從您的GetAllCategoriesAndSubcategories返回完全填充的List。然後你的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

謝謝,讓我試試這個... – 2012-04-06 09:53:16

+0

多一個查詢..看到我更新的問題。我正在使用它作爲我的存儲庫模式實現。這是正確的方法.....建議我一些好的資源使用L2S的好處和回購模式 – 2012-04-06 10:47:18

1

有在代碼中的兩個問題。

該錯誤的直接原因是Brett Veenstra所識別的。如果沒有調用ToList(),則返回一個查詢(IQueryable類型)。查詢在被枚舉之前不會被執行(即循環)。您不會在lock塊內執行此操作,而是在使用結果時完成此操作。

Brett對此的補救措施是正確的。在查詢上調用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()方法中處理成員數據上下文。

作爲一個便箋,您的代碼還有另一個問題。它將分兩步執行。首先它會得到所有的父母,然後爲每個父母它將再次擊中數據庫要求其子女。有超過幾十的父母,這將是一個性能問題。

在linq-to-sql中執行此操作的正確方法是請求所有的孩子,執行ToList(),然後執行LINQ-to-objects GroupBy()。我前一段時間寫了一篇關於它的blog entry

+0

多一個查詢..看到我更新的問題。我正在使用它作爲我的存儲庫模式實現。這是正確的方法.....建議我一些很好的資源,以利用L2S和回購模式的好處 – 2012-04-06 10:47:55

+1

如果您有其他問題,請發佈一個新問題,而不是添加到當前的問題。我的2c重新編譯linq-to-sql和repository就是linq-to-sql *本身就是一個倉庫。我認爲沒有必要將它包裝在另一個存儲庫中。 – 2012-04-06 10:50:20

+0

您能否爲我提供一些很好的鏈接或參考L2S ....感謝 – 2012-04-06 10:53:03

1

是,同意ToList

原因:

「的IEnumerable」 在C#代碼,即LINQ到對象執行的所有操作。這意味着所有的動作都將在C#中發生,因此它在本質上是連通的

一旦您使用IEnumerable調用數據,所有數據都將從數據庫中提取併發送到.net。這會嚴重降低性能(例如,數據庫索引不會被linq-to-objects使用),但另一方面,linq-to-objects更靈活,因爲它可以執行任意C#代碼,而不受限於什麼您的linq提供程序可以轉換爲SQL。

+0

其實,我使用Resharper進行代碼清理和重構等。所以我使用IList或List 作爲返回類型,它建議我使用IEnumerable來代替。一般來說,我返回IList的綁定目的.. – 2012-04-06 10:32:41

+0

阿漢,這是否解決您的問題? – nalaiqChughtai 2012-04-06 10:40:09

+0

正如我所說的,這種情況非常罕見或非常糟糕,所以我不能說它得到解決或不。但我認爲,我必須接受答案......再多一次查詢......查看我更新的問題。我正在使用它作爲我的存儲庫模式實現。這是正確的方法.....建議我一些好的資源,以利用L2S和回購模式的好處 – 2012-04-06 10:43:53