我有一个基于某些参数的方法,在给定字符串列表的两个日期之间找到“事务”。当列表是> 1000,我尝试迭代列表时出现堆栈溢出异常。
这是我的代码
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 :(得分: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));
}
或没有实例化空列表......
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>();
}
或保持懒惰......(编辑使用懒惰)
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>();
}
}
答案 1 :(得分: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()
。但是你绝对不需要创建匿名对象并将它们复制到本地列表。
答案 2 :(得分: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子句中使用了一个列表存在某种限制,这最终成为一个更好的解决方案因为我限制了用户代码,然后做了一个简单的过滤器来获取那些在相关代码清单。