原起:
不久前,我們 3A
站台有出現資料重複顯示的問題,去查才發現是發生在 LINQ 的 join 上,這邊直接開
Console 範例程式講解,用 class 來代表資料表的欄位架構,有兩個
class,Performance 跟 Review
internal class Program
{
class Performance
{
public int SN { get; set; }
public string Name { get; set; }
public Performance(int sN, string name)
{
SN = sN;
Name = name;
}
public override string ToString()
{
return $"SN:{SN}, Name:{Name}";
}
}
class Review
{
public int PerformanceSN { get; set; }
public string Name { get; set; }
public bool IsPass { get; set; }
public Review(int performanceSN, string name, bool isPass)
{
PerformanceSN = performanceSN;
Name = name;
IsPass = isPass;
}
public override string ToString()
{
return $"PerformanceSN:{PerformanceSN}, Name:{Name}, IsPass:{IsPass}";
}
}
}
Performance 有 SN,代表流水號,Name 是表演者的名字。Review
會有 PerformanceSN,用來表示它對應到的是哪筆 Performance (SN),Name
是評審的名字,IsPass 代表有無通過。Performance 跟 Review
是一對多的關係。
再來是加入產測試資料的 method,由於它們再來會在 Main
裡被呼叫,所以是 static
internal class Program
{
class Performance
{
public int SN { get; set; }
public string Name { get; set; }
public Performance(int sN, string name)
{
SN = sN;
Name = name;
}
public override string ToString()
{
return $"SN:{SN}, Name:{Name}";
}
}
class Review
{
public int PerformanceSN { get; set; }
public string Name { get; set; }
public bool IsPass { get; set; }
public Review(int performanceSN, string name, bool isPass)
{
PerformanceSN = performanceSN;
Name = name;
IsPass = isPass;
}
public override string ToString()
{
return $"PerformanceSN:{PerformanceSN}, Name:{Name}, IsPass:{IsPass}";
}
}
/// <summary>
/// 產 Performance 資料
/// </summary>
/// <returns></returns>
static List<Performance> _CreatePerformance()
{
List<Performance> listReturn = new List<Performance>();
listReturn.Add(new Performance(1, "鳥旭"));
listReturn.Add(new Performance(2, "薯泥"));
listReturn.Add(new Performance(3, "阿祈"));
listReturn.Add(new Performance(4, "肥伶"));
return listReturn;
}
/// <summary>
/// 產 Review 資料
/// </summary>
/// <returns></returns>
static List<Review> _CreateReview()
{
List<Review> listReturn = new List<Review>();
listReturn.Add(new Review(1, "評審一", true));
listReturn.Add(new Review(2, "評審二", true));
listReturn.Add(new Review(3, "評審三", true));
listReturn.Add(new Review(4, "評審四", false));
return listReturn;
}
}
假如遊戲規則是,只要有任何一個 Review 有 Pass,對應的
Performance 就可以晉級。現在,如果想從資料中抓出有通過的 Performance,並列印出來,我們可以用 join
來達成
static void Main(string[] args)
{
List<Performance> listAllPerformance = _CreatePerformance();
List<Review> listAllReview = _CreateReview();
List<Performance> listPassedRequest =
(from performance in listAllPerformance
join review in listAllReview on performance.SN equals review.PerformanceSN
where review.IsPass
select performance).ToList();
foreach (Performance request in listPassedRequest)
{
Console.WriteLine(request);
}
Console.ReadKey();
}
目前資料的情況是一筆 Review 對應到一筆
Performance,輸出的結果在預期中
問題:
如果修改 _CreateReivew 方法,再多加一位 Review 進來
static List<Review> _CreateReview()
{
List<Review> listReturn = new List<Review>();
listReturn.Add(new Review(1, "評審一", true));
listReturn.Add(new Review(2, "評審二", true));
listReturn.Add(new Review(3, "評審三", true));
listReturn.Add(new Review(4, "評審四", false));
listReturn.Add(new Review(1, "評審五", true)); //新加入的
return listReturn;
}
之後再執行程式,會發現 "鳥旭"
變兩個,產生重複的資料 (linq 的 join 是 inner join)
Linq GroupBy:
SQL 的 SELECT 有 DISTINCT 的功能,但 Linq
似乎沒有,我後來去查,在這邊找到解答,解答就是用 GroupBy,程式改成
static void Main(string[] args)
{
List<Performance> listAllPerformance = _CreatePerformance();
List<Review> listAllReview = _CreateReview();
List<Performance> listPassedRequest =
(from performance in listAllPerformance
join review in listAllReview on performance.SN equals review.PerformanceSN
where review.IsPass
select performance)
.GroupBy(o => o.SN)
.Select(o => o.First())
.ToList();
foreach (Performance request in listPassedRequest)
{
Console.WriteLine(request);
}
Console.ReadKey();
}
第11行 : 依據 Performance 的 SN 來分群。
第12行 : 用 Linq 的 Select,還有 IGroup<int, Performance> 的 First() 來取得每群的第一個 Performance。
就能達成效果
沒有留言:
張貼留言