是否存在排列

时间:2013-02-18 14:59:57

标签: c# sql linq linq-to-sql

我试图找出linq中对sql的正确查询,但我只是想弄清楚如何这样做。可以说我有一张下面的表(这个表基本上是一对多的关系)

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到sql查询找到对employeeId 5和6有的supervisorId。查询只返回2。我可以使用2 where子句,但是让我说我​​想输入3个employeeIds,我的查询将不得不修改。如果一个匹配的SupervisorId存在传递的排列(例如,在这种情况下为5,6,8),则结果将为null或为空。

该功能如下所示:

int FindSuperVisorId(List<int> employeeIds);

我真的不知道在这种情况下从linq到sql的起点。

由于

3 个答案:

答案 0 :(得分: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查询。如果您需要检查只有一个匹配的主管,最好在返回的主管列表上调用ToList(),如FindSupervisorId。

由于调用Except异常,尝试使用LINQ to SQL执行相同的操作失败 'NotSupportedException:除了Contains运算符之外,本地序列不能用于查询运算符的LINQ to SQL实现。'

答案 1 :(得分:1)

所以我很确定这个查询应该转换为LINQ to SQL的属性,但我不完全确定。

首先,我们由主管分组,以便我们为该主管提供一系列员工。然后,我们将Except与您感兴趣的员工一起用于两个方向。如果这两个Except调用的计数为零,则这些集合完全相等。有更有效的方法可以确定两个集合在linq到对象中是否相等,但我怀疑它们是否会正确转换为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();

答案 2 :(得分:0)

一种可能性:

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)));
}