簡體   English   中英

如何在 Linq 中有效地進行內部連接和填充屬性?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM