[英]how to do an inner join and populate property efficiently in Linq?
假設我們有以下代碼:
Category[] categoriesOne = new Category[] {
// each instance contains a lot of properties but without Desc property being set
// the content of Desc property is only available in categoriesTwo
new Category { IdCategory = 1, Name = "Pasta", ...},
new Category { IdCategory = 2, Name = "Beverages", ...},
new Category { IdCategory = 3, Name = "Other food", ...},
};
Category[] categoriesTwo = new Category[] { // only two properties in each instance
new Category { IdCategory = 1, Desc = "made in Italy"},
new Category { IdCategory = 2, Desc = "made in Germany"},
};
public class Category
{
public int IdCategory { get; set; }
public String Name { get; set; }
public String Desc{ get; set; }
// ... many more properties such as barcode, supplier, country, countrycode ... etc
}
我想做一個內部連接並填充 Desc 屬性,所以作為 IEnumerable 的返回實例應該是:
{
new Category { IdCategory = 1, Name = "Pasta", Desc = "made in Italy"},
new Category { IdCategory = 2, Name = "Beverages", Desc = "made in Germany"}
}
它看起來是一個非常簡單的任務,我們通常可以做到:
var query = categoriesOne.Join(categoriesTwo, c1 => c1.IdCategory, c2 => c2.IdCategory, (c1, c2) => new { c1, c2 });
foreach (var item in query)
{
item.c1.Desc = item.c2.Desc;
}
但它看起來不是一個好的/有效的方法,我們有沒有更優雅的方法,所以我們可以一次性完成:
var query = from c1 in categoriesOne
join c2 in categoriesTwo on c1.IdCategory equals c2.IdCategory into groups
???
請注意,我不能這樣做:
var result = (from c1 in categoriesOne
join c2 in categoriesTwo on c1.IdCategory equals c2.IdCategory
select new Category
{
IdCategory = c1.IdCategory,
Name = c1.Name,
Desc = c2.Desc
// ... too many properties from categoriesOne, this approach is tedious
}
).ToList();
因為 Category 類包含很多屬性,所以基本上我想保留categoriesOne
中的所有屬性(除了 Desc 屬性,其內容僅在categoriesTwo
中可用
我想到的關於合並兩個對象的問題是,誰是源,誰是目標,或者都是實體源,應該創建一個新目標? 在select
子句中,您必須做出此決定。 為了避免繁瑣的代碼行,您可以使用一些反射材料並從一個或多個源讀取所有屬性,獲取第一個非默認值並將其寫入所需的目標。
public static class Helper
{
public static T Merge<T>(T target, params T[] sources) where T : class, new()
{
if (target == null)
target = new T();
var props = typeof(T).GetProperties()
.Where(prop => prop.CanRead && prop.CanWrite);
foreach (var prop in props)
{
var value = sources.Select(source => prop.GetValue(source))
.FirstOrDefault(value => value != default);
prop.SetValue(target, value);
}
return target;
}
}
使用這個助手,您應該能夠編寫如下內容:
var result = (from c1 in categoriesOne
join c2 in categoriesTwo on c1.IdCategory equals c2.IdCategory
select Helper.Merge(null, c1, c2)
).ToList();
或者
var result = (from c1 in categoriesOne
join c2 in categoriesTwo on c1.IdCategory equals c2.IdCategory
select Helper.Merge(c1, c2)
).ToList();
取決於您是想從這兩個實例中創建一個新實例還是操縱第一個實例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.