3

linq to sqlで適切なクエリを見つけようとしていますが、その方法がわかりません。次のようなテーブルがあるとしましょう(このテーブルは基本的に1対多の関係です)

Id (PK) | SupervisorId | EmployeeId
    1          1            5
    2          1            6
    3          1            7
    4          2            5
    5          2            6
    6          3            7
    7          4            7
    8          4            8

linq to sqlクエリでemployeeId5と6のsupervisorIdを検索したいのですが、クエリは2のみを返します。2つのwhere句を使用することもできますが、3つのemployeeIdを入力したい場合は、クエリを変更する必要があります。一致した1つのSupervisorId(この場合は5,6,8など)に渡された順列が存在しない場合、結果はnullまたは空になります。

関数は次のようになります。

int FindSuperVisorId(List<int> employeeIds);

このタイプのシナリオでは、linqtosqlのどこから始めればよいのか本当にわかりません。

ありがとう

4

3 に答える 3

1

次のように、テーブルを多対多の関係としてモデル化する必要がありました。

CREATE TABLE [dbo].[Employee](
    [Name] [nvarchar](50) NOT NULL,
    [Id] [int] IDENTITY(1,1) NOT NULL,
 CONSTRAINT [PK_Employee] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)

CREATE TABLE [dbo].[SupervisorEmployees](
    [SupervisorId] [int] NOT NULL,
    [EmployeeId] [int] NOT NULL,
 CONSTRAINT [PK_SupervisorEmployees] PRIMARY KEY CLUSTERED 
(
    [SupervisorId] ASC,
    [EmployeeId] ASC
)
GO

ALTER TABLE [dbo].[SupervisorEmployees]  WITH CHECK ADD  CONSTRAINT [FK_SupervisorEmployees_Employee] FOREIGN KEY([SupervisorId])
REFERENCES [dbo].[Employee] ([Id])
GO

ALTER TABLE [dbo].[SupervisorEmployees] CHECK CONSTRAINT [FK_SupervisorEmployees_Employee]
GO

ALTER TABLE [dbo].[SupervisorEmployees]  WITH CHECK ADD  CONSTRAINT [FK_SupervisorEmployees_Employee1] FOREIGN KEY([EmployeeId])
REFERENCES [dbo].[Employee] ([Id])
GO

ALTER TABLE [dbo].[SupervisorEmployees] CHECK CONSTRAINT [FK_SupervisorEmployees_Employee1]
GO

次に、最初にEntity Frameworkデータベースを使用します(残念ながら、Linq to SQLではありません)。次のLINQPadコードは正常に機能します。

void Main()
{
    FindSupervisorIds( new List<int>{5,6} ).Dump();
}

IEnumerable<int> FindSupervisorIds(List<int> employeeIds)
{
    // two Excepts to do 'sequence equals'
    var supervisors = Employees.Where (e =>
        !e.Employees.Select (em => em.Id).Except(employeeIds).Any()
        && !employeeIds.Except(e.Employees.Select (em => em.Id)).Any() 
    );

    return supervisors.Select (s => s.Id).Distinct();
}

int? FindSupervisorId(List<int> employeeIds)
{
    var supervisors = FindSupervisorIds(employeeIds).ToList();

    if(supervisors.Count == 1)
    {
        return supervisors.First ();
    }

    return null;
}

FindSupervisorIdsは、単一のSQLクエリを生成します。一致するスーパーバイザーが1つしかないことを確認する必要がある場合は、FindSupervisorIdのように、返されたスーパーバイザーのリストでToList()を呼び出すのがおそらく最善です。

LINQ to SQLで同じことを行おうとすると、Exceptの呼び出しが原因で失敗します。ただし、 「NotSupportedException:ローカルシーケンスは、Contains演算子を除くクエリ演算子のLINQtoSQL実装では使用できません。」

于 2013-02-18T15:17:15.747 に答える
1

したがって、このクエリはプロパティをLINQ to SQLに変換する必要があると確信していますが、完全にはわかりません。

したがって、最初にスーパーバイザーごとにグループ化して、そのスーパーバイザーの従業員のシーケンスを作成します。次にExcept、興味のある従業員と双方向で使用します。これらの呼び出しの両方のカウントExceptがゼロの場合、セットは完全に等しくなります。linq-to-objectsで2つのセットが等しいかどうかを判断するより効率的な方法がありますが、SQLコードに適切に変換されるとは思えません。

var supervisorId = table.GroupBy(item => item.SupervisorId)
    .Select(group => new
    {
        additionalItems = group.Select(item => item.EmployeeId).Except(employees),
        missingItems = employees.Except(group.Select(item => item.EmployeeId)),
        group = group
    })
    .Where(queries => queries.additionalItems.Count() == 0
    && queries.missingItems.Count() == 0)
    .Select(queries => queries.group.Key)//gets the supervisorID
    .FirstOrDefault();
于 2013-02-18T15:27:14.350 に答える
0

1つの可能性:

public int FindSuperVisorId(IEnumerable<Employee> employes)
{
    var distinctSupervisors = employes.Select(e => e.SuperVisor).Distinct();
    var superVisor = distinctSupervisors.Where(supervisor => employes.All(employee => employee.SuperVisor.Equals(supervisor))).FirstOrDefault();
    return superVisor;
}

同じスーパーバイザーのすべての一致が必要な場合:

public IEnumerable<int> FindSuperVisorId(IEnumerable<Employee> employes)
{
    var distinctSupervisors = employes.Select(e => e.SuperVisor).Distinct();
    var equalSupervisors = distinctSupervisors .Where(supervisor => employes.All(employee => employee.SuperVisor.Equals(supervisor)));
    return equalSupervisors;
}

または直接:

public IEnumerable<int> FindSuperVisorId(IEnumerable<Employee> employes)
{
    return employes.Select(e => e.SuperVisor).Distinct()
        .Where(supervisor => employes.All(employee => employee.SuperVisor.Equals(supervisor)));
}
于 2013-02-18T15:11:59.760 に答える