我有以下计算客户帐户状态的运行总计,但是他的第一个值总是添加到自身,我不知道为什么 - 虽然我怀疑我错过了一些明显的东西:
decimal? runningTotal = 0;
IEnumerable<StatementModel> statement = sage.Repository<FDSSLTransactionHistory>()
.Queryable()
.Where(x => x.CustomerAccountNumber == sageAccount)
.OrderBy(x=>x.UniqueReferenceNumber)
.AsEnumerable()
.Select(x => new StatementModel()
{
SLAccountId = x.CustomerAccountNumber,
TransactionReference = x.TransactionReference,
SecondReference = x.SecondReference,
Currency = x.CurrencyCode,
Value = x.GoodsValueInAccountCurrency,
TransactionDate = x.TransactionDate,
TransactionType = x.TransactionType,
TransactionDescription = x.TransactionTypeName,
Status = x.Status,
RunningTotal = (runningTotal += x.GoodsValueInAccountCurrency)
});
Run Code Online (Sandbox Code Playgroud)
哪个输出:
29/02/2012 00:00:00 154.80 309.60
30/04/2012 00:00:00 242.40 552.00
30/04/2012 00:00:00 242.40 794.40
30/04/2012 00:00:00 117.60 912.00
Run Code Online (Sandbox Code Playgroud)
凡309.60
第一排的应该是简单154.80
我做错了什么?
编辑:
根据下面的ahruss的评论,我Any()
在我的视图中调用结果,导致第一次被评估两次 - 解决我附加ToList()
到我的查询.
谢谢大家的建议
添加一个ToList()
到调用的末尾以避免重复调用选择器.
这是一个带有副作用的有状态LINQ查询,这本质上是不可预测的.在代码的其他地方,你调用的东西导致第一个元素被评估,比如First()
或Any()
.一般来说,在LINQ查询中存在副作用是危险的,当你发现自己需要它们时,是时候考虑它是否应该只是一个foreach
.
这是对LINQ查询进行评估的结果:在您实际使用查询结果之前,集合中没有任何实际情况发生.它不评估任何元素.相反,它存储抽象表达式树或仅存储评估查询所需的委托.然后,它仅在需要结果时评估这些结果,除非您明确存储结果,否则它们会在之后被丢弃,并在下次重新评估.
所以这就提出了为什么每次都有不同结果的问题?答案是,runningTotal
只是第一次初始化.之后,它的值是上次执行查询后的值,这可能会导致奇怪的结果.
这意味着问题可能很容易就是"为什么总数应该是它应该是的两倍?" 如果提问者做了这样的事情:
Console.WriteLine(statement.Count()); // this enumerates all the elements!
foreach (var item in statement) { Console.WriteLine(item.Total); }
Run Code Online (Sandbox Code Playgroud)
因为获得序列中元素数量的唯一方法是实际评估所有元素.
同样,在这个问题中实际发生的事情是某处有像这样的代码:
if (statement.Any()) // this actually involves getting the first result
{
// do something with the statement
}
// ...
foreach (var item in statement) { Console.WriteLine(item.Total); }
Run Code Online (Sandbox Code Playgroud)
这似乎是无害的,但是如果你知道LINQ和IEnumerable是如何工作的,你知道它.Any()
基本上是相同的.GetEnumerator().MoveNext()
,这使得它更需要获得第一个元素.
这一切都归结为LINQ基于延迟执行的事实,这就是解决方案使用的原因ToList
,它绕过了它并强制立即执行.
归档时间: |
|
查看次数: |
319 次 |
最近记录: |