1

次の LINQ クエリを (WCF Data Services を使用して) より適切に設計する方法についてアドバイスを求めています。要件は、ComboBox を介して従業員のリストを表示することです。

DB テーブルの構造は次のとおりです。

従業員は多くのプロジェクトに割り当てることができ、プロジェクトは多くの従業員を持つことができます。この関係は、次の 3 つのテーブルを介して設計されています[Employees] 1--* [EmployeeProjects] *--1 [Projects]。ドット ネーションでは、オブジェクト ツリーをトラバースすると、次のようになりますEmployee.EmployeeProjects.Project

次の LINQ ステートメントは のリストを返しますEmployeeProjectsが、私が求めているのは、これらの特定のプロジェクトの一部である Employee のリストです。理想的には、 を実行するのは理にかなっていますが、リンク (多数)IQueryable<Employee>のために LINQ ステートメントを構造化する方法がわかりません。EmployeeProjects私のジレンマがわかりますか?

IQueryable<EmployeeProject>以下の LINQ ステートメントからわかるように、従業員側とプロジェクト側はどちらも 1 つの関係であるため、「多」の側面に対処する必要がないため、実行します。のリストを取得した後EmployeeProjects、それに対して別の.Select()ステートメントを実行して、最終的に求めているもの、つまり一意の従業員名のリストを返し.Select(results => results.Employee.Name).Distinct()ます。

private IQueryable<EmployeeProject> GetEmployeeProjects()
{
    var employeeProjects =  service
        .CustomQuery<EmployeeProject>()
        .Where(et => ep.Project.Name == "TrackerX 43" ||
                     ep.Project.Name == "AccountingX 11" ||
                     ep.Project.Name == "TopX 2" ||
                     ep.Project.Name == "SiteX 32" ||
                     ep.Project.Name == "BuildingX 3" ||
                     ep.Project.Name == "ReportX 321" ||
                     ep.Project.Name == "PrototypeX 78" ||
                     ep.Project.Name == ... more ...)
        .OrderBy(ep => ep.Employee.Name)
        .Select(ep => new EmployeeProject
        {
            Id = ep.Id
            Project = new Project
            {
                Name = ep.Project.Name
            },
            Employee = new Employee
            {
                Id = ep.Employee.Id,
                Name = ep.Employeet.Name
            }
        });

    return employeeProjects;
}

これをより良く設計するためのアドバイスをいただければ幸いです。

4

2 に答える 2

2

新しいものを作成する必要がありますEmployeeProjectか、それとも既存のものを簡単に返すことができますか?

できることの 1 つは、文字列を配列に結合して、次のように比較することです。

//Move inside the method call if you need it to be dynamic.
private readonly string[] compareProjectNames = new[]
{ 
   "AccountingX 11", "TopX 2", "SiteX 32", 
   "BuildingX 3", "ReportX 321", "PrototypeX 78"
};
private IQueryable<EmployeeProject> GetEmployeeProjects()
{
    var employeeProjects =  service.CustomQuery<EmployeeProject>()
        .Where(et => compareProjectNames.Contains(ep.Project.Name))
        .OrderBy(ep => ep.Employee.Name)
        .Select(ep => new EmployeeProject
        {
            Id = ep.Id,
            Project = new Project
            {
                Name = ep.Project.Name
            },
            Employee = new Employee
            {
                Id = ep.Employee.Id,
                Name = ep.Employee.Name
            }
        });
    return employeeProjects;
}

編集:

投稿をもう少し注意深く読んだ後、このようなものを探して、明確なプロジェクト名を見つけることもできます

List<EmployeeProject> employeeProjects = new List<EmployeeProject>();
employeeProjects
   .GroupBy(et => et.Project.Name)
   .Select(grp => grp.First());

または、1 つのステートメントで

List<EmployeeProject> employeeProjects = new List<EmployeeProject>();
employeeProjects
        .Where(et => compareProjectNames.Contains(et.Project.Name))
        .GroupBy(cust => cust.Project.Name) //groups them by name, so no need to order
        .Select(grp => grp.First()) //selects the first distinct name per group
        .Select(ep => new EmployeeProject
        {
            Id = ep.Id,
            Project = new Project
            {
                Name = ep.Project.Name
            },
            Employee = new Employee
            {
                Id = ep.Employee.Id,
                Name = ep.Employee.Name
            }
        });
于 2013-03-09T00:12:12.657 に答える
0

サーバー側で EF を使用する場合、EmployeeProject テーブルをクライアントから完全に隠すことができるはずです。EF は、DB 構造を 2 つのエンティティ セット (従業員とプロジェクト) に変換し、それらの間に多対多の関係を持たせることができます (詳細には、2 つの 1 対多の一方向の関係が作成されます)。

したがって、クライアントからは、各インスタンスが、従業員が参加するプロジェクトのリストであるプロパティ Projects を持つ Employees エンティティ セットのように見えます。同様に、各インスタンスが従業員のリストであるプロパティ Employees を持つエンティティ セット Projects のように見えます。そのプロジェクトに割り当てられます。

次に、上記のクエリははるかに単純になる可能性があります (短縮のために URL 表記を使用すると、LINQ バージョンは一種の明白であり、プロジェクト名のリストも単純化されます)。

~/Projects?$filter=(Name eq 'TopX 2') または (Name eq 'SiteX 32')&$expand=Employess

これにより、指定された名前のすべてのプロジェクトと、各プロジェクトに割り当てられたすべての従業員が取得されます。

これは、中央のテーブルが純粋に他の 2 つのテーブルを結合するために存在することを前提としています。接続に関する追加情報も格納している場合、これは機能しません。

于 2013-03-09T21:47:56.253 に答える