Use EF-Core to Join
目錄
EF Core 中使用 Join
以下操作均使用 EF Core 5.0 以下程式碼範例皆為 EFCore.ToList() 執行前的 IQueryable 操作,也就是仍在組合 SQL 語法的階段 不管使用哪種寫法,皆應盡可能減少巢狀操作
Use LinQ Join
1 Linq Join 的參考資料
2 多欄位匹配
- 寫法是 Call Method 形式的 Linq,而非參考資料中使用的關鍵字形式的寫法
 - Key 為多欄位的 Key,對應關係如下
- tableA.SectName = tableB.SessionName
 - tableA.DistName = tableB.AreaName
 
 
private IQueryable<OutPutEntity> JointToOutPutEntity(
            IQueryable<TableA> tableADataList,
            IQueryable<TableB> tableBDataList)
{
    return tableADataList.Join(tableBDataList,
                                // Join 的第二個參數為 TableA 中要用來處理匹配判斷的欄位
                                tableA => new ValueTuple<string, string>( tableA.SectName,    tableA.DistName),
                                // Join 的第三個參數為 TableB 中要用來處理匹配判斷的欄位
                                tableB => new ValueTuple<string, string>( tableB.SessionName, tableB.AreaName),
                                (tableA , tableB) => new OutPutEntity
                                {
                                    LandCode = tableA.LandCode,
                                    CurrentValue = tableA.CurrentValue,
                                    CurrentPrice = tableA.CurrentPrice,
                                    SectName = tableB.SessionId,
                                    DistName = tableB.ZipCode,
                                });
}另一種寫法,如果要將 Join 好的 Table 欄位全數輸出的話可以使用此寫法
private IQueryable<OutPutEntity> JointToOutPutEntity(
            IQueryable<TableA> tableADataList,
            IQueryable<TableB> tableBDataList)
{
    return tableADataList.Join(tableBDataList,
                                // Join 的第二個參數為 TableA 中要用來處理匹配判斷的欄位
                                tableA => new { tableA.SectName,    tableA.DistName},
                                // Join 的第三個參數為 TableB 中要用來處理匹配判斷的欄位
                                tableB => new { tableB.SessionName, tableB.AreaName},
                                (tableA , tableB) => new { tableA, tableB });
    //=====非 Method 寫法如下=======
    return from tableAData in tableADataList
                 join tableBData in tableBDataList on new
                     {
                         fieldA = tableAData.SectName, fieldB = tableAData.DistName
                     }
                     equals new
                     {
                         fieldA = tableBData.SessionName, fieldB = tableBData.AreaName
                     }
                 select new { tableAData, tableBData };
}3 單欄位匹配
- 寫法是 Call Method 形式的 Linq,而非參考資料中使用的關鍵字形式的寫法
 - Key 為單一欄位的 Key,對應關係如下
- tableA.SectName = tableB.SessionName
 
 
private IQueryable<OutPutEntity> JointToOutPutEntity(
            IQueryable<TableA> tableADataList,
            IQueryable<TableB> tableBDataList)
{
    return tableADataList.Join(tableBDataList,
                                tableA => tableA.SectName,
                                tableB => tableB.SessionName,
                                (tableA , tableB) => new OutPutEntity
                                {
                                    LandCode = tableA.LandCode,
                                    CurrentValue = tableA.CurrentValue,
                                    CurrentPrice = tableA.CurrentPrice,
                                    SectName = tableB.SessionId,
                                    DistName = tableB.ZipCode,
                                });
}Select To Object
private IQueryable<OutPutEntity> JointToOutPutEntity(
            IQueryable<TableA> tableADataList,
            IQueryable<TableB> tableBDataList)
{
    return tableADataList.Select(tableAData => new OutPutEntity()
                                {
                                    A = tableAData.SomeField,
                                    B = tableBDataList.FirstOrDefault()?.SomeField
                                    TableBOneRow = tableBDataList.FirstOrDefault() //TableBOneRow 的型別為 TableB
                                    //下面這種寫法會無法使用
                                    //TableBOneRows = tableBDataList //TableBOneRow 的型別為 IEnumerable<TableB>
                                });
}Use LinQ SelectMany
當需要組合多個 Table 時,可使用 SelectMany 來處理。 當使用 SelectMany 後,可以建立極為複雜的可測試查詢 (因為依賴了 IQueryable 與 IEnumerable,而非 SQL),但是會有一定的開發、維護難度,需要注意。
private IQueryable<OutPutEntity> JointToOutPutEntity(
            IQueryable<TableA> tableADataList,
            IQueryable<TableB> tableBDataList)
{
    return tableADataList.SelectMany(tableAData => tableBDataList.Where(tableBData => tableBData.BId == tableAData.AId)
                                                                 .DefaultIfEmpty(), // 這個設定很重要,會影響 Sql 組成與底下的輸出設定
                                     (tableAData, tablaBData) => new { tableAData, tableBData });
}