Linq to Sql-祖先を見つけるための階層クエリ
-
04-07-2019 - |
質問
EmployeeIdが与えられた場合、どのようにしてLinq to Sqlクエリを作成して、従業員のすべての祖先を見つけることができますか?各EmployeeIdには、関連付けられたSupervisorIdがあります(以下を参照)。
たとえば、EmployeeId 6(フランクブラック)の祖先のクエリは、Jane Doe、Bob Smith、Joe Bloggs、およびHead Honchoを返す必要があります。
必要に応じて、すべての従業員のリストをキャッシュしてパフォーマンスを改善できます。
更新:
このタスクを達成するために、次の粗雑なメソッドを作成しました。 employee.Supervisorの関係をルートノードまでたどります。ただし、これは従業員ごとに1つのデータベース呼び出しを発行します。誰もがより簡潔な、またはより高性能な方法を持っていますか?ありがとう。
private List<Employee> GetAncestors(int EmployeeId)
{
List<Employee> emps = new List<Employee>();
using (L2STestDataContext dc = new L2STestDataContext())
{
Employee emp = dc.Employees.FirstOrDefault(p => p.EmployeeId == EmployeeId);
if (emp != null)
{
while (emp.Supervisor != null)
{
emps.Add(emp.Supervisor);
emp = emp.Supervisor;
}
}
}
return emps;
}
解決
まず、 LINQ拡張メソッドプロジェクト。コードの簡素化に役立つと思います。
ここでの問題は、これにより階層内の各ノードに対してデータベース呼び出しが作成されることです。例の場合、データベースへの往復が5回あります。
別のパスに進み、ストアドプロシージャを作成してそれを行い、 Employee
オブジェクトのセット全体を返します。返す前にオブジェクトを切断する(コンテキストを破棄する)ため、ストアドプロシージャの結果セットから新しいオブジェクトを作成するだけです。
他のヒント
Employeeテーブル全体の読み込みを回避する(ただし、縦の深さは制限されている)シンプルなソリューションは...
var emps = dc.Employees.Where(e => (e.EmployeeId == EmployeeId) ||
(e.SupervisorId == EmployeeId) ||
(e.Supervisor.SupervisorId == EmployeeId) ||
(e.Supervisor.Supervisor.SupervisorId == EmployeeId) ||
...);
最終的に、共通テーブル式を使用してフラット化する必要があります階層ですが、LINQ to SQLは現在これをサポートしていません。独自の拡張メソッドの作成を検討できます(Omerのライブラリにあるようなものですが、サーバー側の実行をサポートするためにIEnumerableの代わりにIQueryableを使用します)。