2011-11-10 178 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(); 

阿米爾。