2011-11-10 207 views
1

我有下面的代码在LINQ的GroupBy选择设置属性:尝试使用循环

public class Report 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public decimal Sales { get; set; } 
} 

var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name }).Select(x => new Report { Id = x.Key.Id, Name = x.Key.Name }); 

foreach (var item in result) 
{ 
    item.Sales = anotherColletion.FirstOrDefault(x => x.Id == item.Id).Sales; 
} 

我不能销售产权这种方式设置为任意值。即使我尝试:

foreach (var item in result) 
{ 
    item.Sales = 50; 
} 

不过,如果我使用下面的代码它的工作原理设置属性:

var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name }).Select(x => new Report { Id = x.Key.Id, Name = x.Key.Name, Sales = 50 }); 

设计是这样吗?

回答

5

问题是LINQ查询是懒惰的(“延迟执行”)。你设置foreach循环中查询的每个结果的属性,但这些结果基本上会消失在空气中。 当你列举查询的结果再次foreach(你还没有告诉我们),是重新执行查询后,结果重建,有效地撤销更改。请记住,查询只是如何产生结果的规范,而不是结果本身。

一个简单的修复就是将实现为查询首先进入一个集合。

var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name }) 
        .Select(x => new Report { Id = x.Key.Id, Name = x.Key.Name }) 
        .ToList(); 

foreach然后将最终突变内存中的集合中的元素,而不是一个懒惰查询的结果,并且因此将是可见的下游。

个人虽然,考虑在查询本身设置属性:

var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name }) 
        .Select(x => new Report 
           { 
            Id = x.Key.Id, 
            Name = x.Key.Name, 
            Sales = anotherCollection.First(a => a.Id == x.KeyId) 
                  .Sales 
            }); 
+0

如果我先执行myItems.ToList(),然后在没有ToList()的情况下执行GroupBy(),那么这样做还是会导致查询重新执行? – Thomas

+0

@Thomas:这应该在技术上有效,因为可变的Report报告对象已经在该阶段创建并实现了。只有分组才会重新执行,而不是创建对象。我强烈建议不要这样做。 – Ani

+0

我将实现myItems.ToList()的原因是因为我想对集合执行多个GroupBy(未包括在此问题中),并使用这些集合进行计算。我的推理是运行一个数据库查询,然后在另一个GroupBy中使用内存集合。请问为什么你不推荐这样做? – Thomas

0

托马斯,你正在使用

var这个结果只是一个查询,当你迭代它,在foreach循环,您正在生成一个新的报告对象,但它不会被“存储”到任何地方。

添加ToArray的()或ToList()来查询的末尾来解决该问题:

var result = myItems.GroupBy(x => new { Id = x.Id, Name = x.Name }).Select(x => new Report { Id = x.Key.Id, Name = x.Key.Name }).ToList(); 

阿米尔。