尝试使用循环在LINQ GroupBy Select中设置属性

时间:2011-11-10 15:32:00

标签: linq

我有以下代码:

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;
}

我无法通过这种方式将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 });

这是设计吗?

2 个答案:

答案 0 :(得分: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
                                  });

答案 1 :(得分: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();  

阿米尔。