c#LINQ to SQL中出现异常
本文关键字:异常 to SQL c#LINQ | 更新日期: 2023-09-27 18:00:23
我有一个方法,它基于一些参数,在给定字符串列表的两个日期之间找到"Transactions"。当列表>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;
}
}
这是堆栈跟踪。。。它超过了visualstudio可以处理的点。
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
我的问题是,我可以用什么方法来处理这个查询,这样我就不必担心堆栈溢出异常了?
似乎是通过迭代大型集合来破坏堆栈,但同时将这些对象添加到列表中,从而产生两个大型但基本相同的集合。相反,只需对接受任何IEnumerable的列表使用AddRange。
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>();
}
或者为了保持懒惰。。。(编辑为使用Lazy)
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>();
}
}
这里有两个大问题-对于每个唯一的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()
。但您绝对不需要创建匿名对象并将它们复制到本地列表中。
好吧,经过一些尝试和错误,并考虑了一些替代方案,我想出了一个似乎效果很好的解决方案。
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子句中使用的列表有某种限制,这最终是一个更好的解决方案,因为我限制了用户代码,然后做了一个简单的过滤器,只获取相关代码列表中的代码。