我有一个包含大约80,000行的POCO类型的IEnumerable 和一个包含行子集的数据库表(L2E / EF4),其中存在“错误/差异”(约5000行,但经常重复以提供约150个不同的条目)
以下代码获取不同VSACode的“错误”,然后尝试更新完整的结果集,更新JUST匹配的行......但它不起作用!
var vsaCodes = (from g in db.GLDIFFLs
select g.VSACode)
.Distinct();
foreach (var code in vsaCodes)
{
var hasDifference = results.Where(r => r.VSACode == code);
foreach (var diff in hasDifference)
diff.Difference = true;
}
var i = results.Count(r => r.Difference == true);
在此代码之后,i = 0
我也试过了:
foreach (var code in vsaCodes)
{
results.Where(r => r.VSACode == code).Select(r => { r.Difference = true; return r; }).ToList();
}
如何更新“结果”以仅设置匹配的差异属性?
答案 0 :(得分:10)
假设results
只是一个查询(您还没有显示),每次迭代它时都会对它进行评估。如果该查询每次都创建新对象,则将不会查看更新。如果它返回对相同对象的引用,那么就可以。
如果您将results
更改为具体化查询结果 - 例如通过将ToList()
添加到最后 - 然后迭代results
将不会发出新查询,您将看到自己的更改。
答案 1 :(得分:2)
我前段时间遇到了同样的错误。问题是linq查询通常是延迟的,并且在您调用它们时不会执行。
“C#2010中 Pro LINQ语言集成查询”中的报价:
“请注意,即使我们只调用了一次查询,结果也是如此 枚举对于每个枚举都是不同的。这是 进一步证明查询是延期的。如果不是,那么 两个枚举的结果都是一样的。这可能是一个 受益或损害。如果您不希望发生这种情况,请使用其中一个 不返回IEnumerable的转换运算符 查询不是延迟的,例如ToArray,ToList,ToDictionary或 ToLookup,用缓存结果创建不同的数据结构 如果数据源发生变化,则不会改变。“
这里有一个很好的解释,有例子:
http://blogs.msdn.com/b/charlie/archive/2007/12/09/deferred-execution.aspx
此致
答案 2 :(得分:0)
在@ jonskeet的回答中非常仔细地解析词语......
如果您的查询只是一个过滤器并且更新了基础源对象,则将重新评估查询,并且可以根据过滤条件排除这些对象,在这种情况下,查询结果将在后续枚举中更改,但基础对象仍将已经更新。
关键是缺少对新类型的投影,只要更新和持久化已更改的对象。
ToList()
是此问题的常用解决方案,如果对新类型进行投影,它将解决问题,但在您的查询过滤但未投影的情况下,事情会变得多云。如果所有内容都是referencing
同一个对象,则查询更新仍然会影响原始源对象。
再次,解析单词,但这些边缘情况可能会让你失望。
public class Widget
{
public string Name { get; set; }
}
var widgets1 = new[]
{
new Widget { Name = "Red", },
new Widget { Name = "Green", },
new Widget { Name = "Blue", },
new Widget { Name = "Black", },
};
// adding ToList() will result in 'static' query result but
// updates to the objects will still affect the source objects
var query1 = widgets1
.Where(i => i.Name.StartsWith("B"))
//.ToList()
;
foreach (var widget in query1)
{
widget.Name = "Yellow";
}
// produces no output unless you uncomment out the ToList() above
// query1 is reevaluated and filters out "yellow" which does not start with "B"
foreach (var name in query1)
Console.WriteLine(name.Name);
// produces Red, Green, Yellow, Yellow
// the underlying widgets were updated
foreach (var name in widgets1)
Console.WriteLine(name.Name);