簡體   English   中英

LINQ 自參考表 SELECT 查詢

[英]LINQ Self Referencing Table SELECT Query

我有一個自引用員工表,這意味着有一個員工的主鍵“EmployeeID”和一個外鍵“SupervisorID”作為父級(主管)。 管理人員處於層級之上,因此他們的 SupervisorID 是 null。 還有一個日期列 (CreatedOn),用於過濾特定日期,但只有經理有日期,而不是他們的員工。 我試圖從特定日期、經理和他們的員工中獲取所有結果,但我無法讓它運行。 我需要使用 LINQ 來實現這一點,但我認為我可以先進行 SQL 查詢,看看我是否能夠以某種方式將其遷移到 Z979E08FD891EBB5526A70C82D741A409 查詢(語法無關)。 但這是非常錯覺,一旦我意識到它和 LINQ 一樣難......我認為這可以通過 CTE 實現,但我根本無法運行自參考。 要么我只找經理,要么什么都沒有……這是一個示例表:

------------------------------------------------------
|EmployeeID|Name    |SupervisorID|CreatedOn          |
|1         |Sanders |NULL        |2019-01-01 16:20:33|
|2         |Flanders|1           |NULL               |
|3         |Andrews |1           |NULL               |
|4         |Ranger  |NULL        |2019-03-20 18:04:56|
|5         |Hammer  |4           |NULL               |
|6         |Enderson|4           |NULL               |
|7         |Larsson |NULL        |2019-10-03 04:55:16|
|8         |Simpson |8           |NULL               |
------------------------------------------------------

可以看到,Sanders (2019-01-01 16:20:33) 有 2 名員工 (Flanders, Andrews),Ranger 2019-03-20 18:04:56 有 2 名員工 (Hammer, Enderson) 和 Larsson (2019 -10-03 04:55:16) 有 1 名員工 (Simpson)

我對 LINQ 一無所獲。 如果我過濾日期,我就沒有辦法過濾員工的初始數據集了。

// This filters by date, but then I can't get the employees without date anymore
employees.Where(e => e.CreatedOn >= '2019-01-01' && e.CreatedOn < '2019-01-02')

// This filters all employees with a parent, but then I can't get the managers anymore and can't filter against a date anymore either
employees.Where(e => e.SupervisorID != null)

我嘗試了加入,但這也不是很好:

from employees m in employees
join e in employees
on m.EmployeeId equals e.SupervisorID
where m.CreatedOn >= '2019-01-01' && m.CreatedOn < '2019-01-02'
select m

適當過濾器的預期結果集將是 Sanders 和他的員工,因為 Sanders 的條目是在 1 月 1 日創建的,並且他的員工在他手下工作:

------------------------------------------------------
|EmployeeID|Name    |SupervisorID|CreatedOn          |
|1         |Sanders |NULL        |2019-01-01 16:20:33|
|2         |Flanders|1           |NULL               |
|3         |Andrews |1           |NULL               |
------------------------------------------------------

有誰知道,我怎么能做到這一點? 我將無法調整數據庫設計,因為我只能讀取並且另一個應用程序推送數據,而我無法更改。

讓我們分別看主管和員工,然后將兩者合並。

監事

對於主管來說,邏輯相當簡單,您可以根據創建日期進行過濾。

var fromDate = new DateTime(2019,1,1);
var untilDate = new DateTime(2019,1,2);

var supervisors = employees
                         .Where(e => e.CreatedOn >= fromDate 
                                  && e.CreatedOn < untilDate )
                         .ToList();

注意:在您的數據集中,只有主管有創建日期。 如果員工也可以有創建日期,則需要顯式過濾掉它們:

var supervisors = employees
                         .Where(e => e.CreatedOn >= fromDate 
                                  && e.CreatedOn < untilDate 
                                  && e.SupervisorID == null)
                         .ToList();

雇員

員工的邏輯稍微復雜一些,但您可以依靠 EF 的導航屬性為您處理連接。

簡而言之,您需要其主管的創建日期在選定范圍內的員工。

var fromDate = new DateTime(2019,1,1);
var untilDate = new DateTime(2019,1,2);

var subordinates = employees
                         .Where(e => e.SupervisorID != null
                                  && e.Supervisor.CreatedOn >= fromDate 
                                  && e.Supervisor.CreatedOn < untilDate )
                         .ToList();

合並兩者

合並這些相當簡單,它有效地執行了supervisorFilter OR subordinateFilter器:

var fromDate = new DateTime(2019,1,1);
var untilDate = new DateTime(2019,1,2);

var supervisorsAndSubordinates = employees
                         .Where(e => 
                                  // Supervisor filter
                                  (
                                       e.CreatedOn >= fromDate 
                                    && e.CreatedOn < untilDate
                                  )
                                  ||
                                  // Subordinate filter
                                  (
                                       e.SupervisorID != null
                                    && e.Supervisor.CreatedOn >= fromDate 
                                    && e.Supervisor.CreatedOn < untilDate
                                  ))
                         .ToList();

這將為您提供您期望的結果集。 請注意,當此結構是遞歸的(即多個“主管的主管”級別)時,解決方案會變得非常困難,但目前在您的示例中並非如此。


使用 join,您可以同時擁有經理及其下屬:

var list = employees.Where(m=> m.CreatedOn >= new DateTime(2019,1,1) && m.CreatedOn < new DateTime(2019,1,2)).Join(employees,sc=> sc.EmployeeId, soc=> soc.SupervisorId, (sc,soc)=> new {left= sc, right=soc}  ).ToList();

我創建了一個小提琴,請查看以下鏈接:

C# 編譯器小提琴

注意:我自己加入了員工,考慮了左側列表的日期過濾器,並加入了右側列表中的 supervisorId。 它顯示經理和他/她各自的員工

你需要一個左外連接

即類似的東西

 var mylist = (from employee in employees
              join r in employees on employee.SupervisorId equals r.EmployeeId  into results                  
              from supervisor in results.DefaultIfEmpty()

               let createdDate = supervisor != null ? supervisor.CreatedOn : employee.CreatedOn                  
               where  createdDate >= new DateTime(2019,1,1) && createdDate < new DateTime(2019,1,2) 
               select employee);

我假設只有兩個級別(即沒有人可以成為主管並擁有主管)。

所有 Linq 方法都是惰性求值的,您應該使用終端方法立即獲得結果。

ToList、ToArray、ForEach 等終端方法...

employees.Where(e => e.SupervisorID != null).ToList()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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