2013-02-21 28 views
3

我有一個基於某些參數的方法在給出一個字符串列表的兩個日期之間找到'Transactions'。當列表大於1000時,我得到一個堆棧溢出異常,試圖迭代列表。LINQ to SQL中的堆棧溢出異常

這裏是我的代碼

public List<string> CodesWithTransactionsBetweenDates(DateTime startInclusive, DateTime endExclusive, List<string> associatedCodes, int marketId) 
    { 
     List<string> codesWithTransactionsInPeriod = new List<string>(); 
     using (var context = new MarketPlaceEntities()) 
     { 
      var transactionList = (from transactions in context.Transactions 
            where 
            associatedCodes.Contains(transactions.User.Code) && 
            transactions.MarketId == marketId && 
            transactions.Date >= startInclusive && 
            transactions.Date < endExclusive 
            group transactions by transactions.User.Code into uniqueIds 
            select new { UserCode = uniqueIds.Key }); 
      foreach (var transaction in transactionList) 
      { 
       codesWithTransactionsInPeriod.Add(transaction.UserCode); 
      } 
      return codesWithTransactionsInPeriod; 
     } 
    } 

這裏是堆棧跟蹤......它會過去的這Visual Studio可以處理點。

System.Data.Entity.dll!System.Data.Query.InternalTrees.BasicOpVisitor.VisitChildren(System.Data.Query.InternalTrees.Node n) + 0x3 bytes 
System.Data.Entity.dll!System.Data.Query.PlanCompiler.GroupAggregateRefComputingVisitor.VisitDefault(System.Data.Query.InternalTrees.Node n) + 0x2b bytes 
System.Data.Entity.dll!System.Data.Query.InternalTrees.BasicOpVisitor.VisitRelOpDefault(System.Data.Query.InternalTrees.RelOp op, System.Data.Query.InternalTrees.Node n) + 0xe bytes 
System.Data.Entity.dll!System.Data.Query.InternalTrees.BasicOpVisitor.VisitApplyOp(System.Data.Query.InternalTrees.ApplyBaseOp op, System.Data.Query.InternalTrees.Node n) + 0xe bytes 
System.Data.Entity.dll!System.Data.Query.InternalTrees.BasicOpVisitor.Visit(System.Data.Query.InternalTrees.OuterApplyOp op, System.Data.Query.InternalTrees.Node n) + 0xe bytes  
System.Data.Entity.dll!System.Data.Query.InternalTrees.OuterApplyOp.Accept(System.Data.Query.InternalTrees.BasicOpVisitor v, System.Data.Query.InternalTrees.Node n) + 0x10 bytes 
System.Data.Entity.dll!System.Data.Query.InternalTrees.BasicOpVisitor.VisitNode(System.Data.Query.InternalTrees.Node n) + 0x14 bytes  
System.Data.Entity.dll!System.Data.Query.InternalTrees.BasicOpVisitor.VisitChildren(System.Data.Query.InternalTrees.Node n) + 0x60 bytes  

我的問題是什麼是一種方法,我可以處理這個查詢,使我不必擔心堆棧溢出異常?

+0

你使用的是什麼版本的Linq?有一個4.0之前的bug可能會導致這種情況發生:http://damieng.com/blog/2009/06/01/linq-to-sql-changes-in-net-40 *「Contains now now detect self-引用IQueryable並且不會導致堆棧溢出「* – 2013-02-21 20:30:21

+0

@MatthewWatson我正在使用.NET Framework 4.0謝謝:) – 2013-02-21 20:42:57

+0

處理堆棧溢出的一般建議:查看調試器中的調用堆棧以查看涉及哪些方法。 – 2013-02-21 21:20:18

回答

0

好的,經過一些試驗和錯誤,並尋找一些替代品,我想出了一個解決方案,似乎工作得很好。

public List<string> CodesWithTransactionsBetweenDates(DateTime startInclusive, DateTime endExclusive, List<string> associatedCodes, int marketId) 
{ 
    using (var context = new MarketPlaceEntities()) 
    { 
     var list = (from transactions in context.Transactions        
       where 
        transactions.MarketId == marketId && 
        transactions.Date >= startInclusive && 
        transactions.Date < endExclusive        
       select transactions.User.Code).Distinct().ToList<string>(); 

     return list.Where(c => associatedCodes.Contains(c)).ToList(); 
    }    
} 

我想有某種與列表限制的where子句中使用,這結束了,因爲我限制了用戶代碼,然後做一個簡單的過濾器,只得到那些更好的解決方案在相關代碼列表中。

+1

找到解決辦法的好工作。我認爲你已經強調了.NET團隊必須處理的一些關於linq懶惰的事情。 – pwnyexpress 2013-02-22 15:51:01

2

看起來好像你通過遍歷大集合來吹捧堆棧,但同時也將這些對象添加到列表中,從而產生兩個大的但基本相同的集合。相反,只需使用AddRange作爲接受任何IEnumerable的列表。

List<string> codesWithTransactionsInPeriod = new List<string>(); 
using (var context = new MarketPlaceEntities()) 
    { 
     return codesWithTransactionsInPeriod.AddRange((from transactions in context.Transactions 
           where 
           associatedCodes.Contains(transactions.User.Code) && 
           transactions.MarketId == marketId && 
           transactions.Date >= startInclusive && 
           transactions.Date < endExclusive 
           group transactions by transactions.User.Code into uniqueIds 
           select uniqueIds.Key)); 
    } 

或不實例化一個空列表...

​​

或保存懶惰......(編輯使用懶惰)

public Lazy<List<string>> LazyCodesWithTransactionsBetweenDates((DateTime startInclusive, DateTime endExclusive, List<string> associatedCodes, int marketId) 
{ 
    return new Lazy<List<string>>(CodesWithTransactionsBetweenDates(startInclusive, endExclusive, associatedCodes, marketId)); 
} 

private List<string> CodesWithTransactionsBetweenDates(DateTime startInclusive, DateTime endExclusive, List<string> associatedCodes, int marketId) 
{ 
    using (var context = new MarketPlaceEntities()) 
    { 
     return (from transactions in context.Transactions 
          where 
          associatedCodes.Contains(transactions.User.Code) && 
          transactions.MarketId == marketId && 
          transactions.Date >= startInclusive && 
          transactions.Date < endExclusive 
          group transactions by transactions.User.Code into uniqueIds 
          select uniqueIds.Key).ToList<string>(); 
    } 
} 
+0

這不編譯,我得到不能轉換類型'無效'爲'列表' – 2013-02-21 20:48:15

+0

請參閱我的編輯更好的方法,應該編譯。第一個示例可能需要在內部linq查詢結束時使用.AsEnumerable()擴展方法。 – pwnyexpress 2013-02-21 20:52:25

+0

我只是嘗試第二個例子,它編譯,但我仍然收到StackOverflowException。 – 2013-02-21 20:54:50

0

您在這裏有兩個大問題 - 對於每個唯一的ID鍵,您正在內存中創建具有單個屬性的新對象。你也有無用的本地列表,你複製所有這些對象。每當列表的容量被填充時,新的內部數組被創建並且所有對象被複制到那裏。

您可以使用IEnumerable進行流處理。在這種情況下,你並不需要保存在內存中的所有數據:

public IEnumerable<string> CodesWithTransactionsBetweenDates(
     DateTime startInclusive, DateTime endExclusive, 
     List<string> associatedCodes, int marketId) 
{ 
    // do not use local list 

    using (var context = new MarketPlaceEntities()) 
    { 
     return from transactions in context.Transactions 
       where associatedCodes.Contains(transactions.User.Code) && 
         transactions.MarketId == marketId && 
         transactions.Date >= startInclusive && 
         transactions.Date < endExclusive 
         group transactions by transactions.User.Code into uniqueIds 
         select uniqueIds.Key; // do not create anonymous object 
    } 
} 

如果需要列表中,您可以在此查詢申請ToList()。但你絕對不需要創建匿名對象並將它們複製到本地列表中。