C# LINQ语句优化-寻求更好设计的建议

C# LINQ语句优化-寻求更好设计的建议,c#,linq,wcf-data-services,odata,C#,Linq,Wcf Data Services,Odata,我正在寻求关于如何更好地设计以下LINQ查询(使用WCF数据服务)的建议。要求通过组合框显示员工列表 DB表结构如下所示: 一个员工可以被分配到许多项目,一个项目可以有许多员工。此关系通过3个表设计:[EmployeeProjects]*--1[Projects]。在dot nation中,如果我正在遍历对象树:Employee.EmployeeProjects.Project private IQueryable<EmployeeProject> GetEmployeeProjec

我正在寻求关于如何更好地设计以下LINQ查询(使用WCF数据服务)的建议。要求通过组合框显示员工列表

DB表结构如下所示:

一个员工可以被分配到许多项目,一个项目可以有许多员工。此关系通过3个表设计:
[EmployeeProjects]*--1[Projects]
。在dot nation中,如果我正在遍历对象树:
Employee.EmployeeProjects.Project

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;
}
下面的LINQ语句返回了一个
员工项目列表
,但我想要的是一个属于这些特定项目的员工列表。理想情况下,执行
IQueryable
是有意义的,但由于
EmployeeProjects
链接(很多),我不知道如何构造我的LINQ语句。你明白我的困境吗

我执行一个
IQueryable
,因为正如您从我下面的LINQ声明中所看到的,我从不需要处理“多”方面的问题,因为员工和项目双方都是1关系。在我获得
员工项目列表后,我对其执行另一个
.Select()
语句,以返回我最终想要的内容,即唯一员工姓名列表,例如
.Select(results=>results.Employee.Name).Distinct()

private IQueryable GetEmployeeProjects()
{
var employeeProjects=服务
.CustomQuery()
.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==…更多…)
.OrderBy(ep=>ep.Employee.Name)
.选择(ep=>new EmployeeProject
{
Id=ep.Id
项目=新项目
{
Name=ep.Project.Name
},
雇员=新雇员
{
Id=ep.Employee.Id,
Name=ep.Employeet.Name
}
});
返回员工项目;
}

如果您对如何更好地设计此项目有任何建议,我们将不胜感激。

您是否需要创建一个新的
EmployeeProject
,或者您是否可以简单地返回现有的项目

您可以做的一件事是将字符串组合到一个数组中,并按如下方式进行比较:

//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;
}
//如果需要动态方法调用,请在方法调用内部移动。
私有只读字符串[]compareProjectNames=new[]
{ 
“AccountingX 11”、“TopX 2”、“SiteX 32”,
“BuildingX 3”、“ReportX 321”、“PrototypeX 78”
};
私有IQueryable GetEmployeeProjects()
{
var employeeProjects=service.CustomQuery()
.Where(et=>compareProjectNames.Contains(ep.Project.Name))
.OrderBy(ep=>ep.Employee.Name)
.选择(ep=>new EmployeeProject
{
Id=ep.Id,
项目=新项目
{
Name=ep.Project.Name
},
雇员=新雇员
{
Id=ep.Employee.Id,
Name=ep.Employee.Name
}
});
返回员工项目;
}
编辑:

在仔细阅读您的帖子之后,您可能也在寻找类似这样的东西,以找到不同的项目名称

List<EmployeeProject> employeeProjects = new List<EmployeeProject>();
employeeProjects
   .GroupBy(et => et.Project.Name)
   .Select(grp => grp.First());
List employeeProjects=new List();
雇员项目
.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
            }
        });
List employeeProjects=new List();
雇员项目
.Where(et=>compareProjectNames.Contains(et.Project.Name))
.GroupBy(cust=>cust.Project.Name)//按名称对它们进行分组,因此无需排序
.Select(grp=>grp.First())//选择每个组的第一个不同名称
.选择(ep=>new EmployeeProject
{
Id=ep.Id,
项目=新项目
{
Name=ep.Project.Name
},
雇员=新雇员
{
Id=ep.Employee.Id,
Name=ep.Employee.Name
}
});

如果在服务器端使用EF,应该能够对客户端完全隐藏EmployeeProject表。EF应该能够将您的DB结构转换为两个实体集(员工和项目),它们之间具有多个关系(具体而言,它将创建两个1-多个单向关系)

因此,从客户端看,它看起来像一个雇员实体集,其中每个实例都有一个属性Projects,这是雇员参与的项目列表。类似地,实体集项目中的每个实例都有一个属性Employees,该属性是分配给该项目的员工列表

然后,上面的查询可能会简单得多(使用URL表示法表示简短,LINQ版本有点明显,还简化了项目名称列表):

~/Projects?$filter=(名称eq'TopX 2')或(名称eq'SiteX 32')&$expand=Employess

这将获得具有指定名称的所有项目,以及每个项目的所有指定员工


这假设中间的表纯粹用于连接其他两个表,如果您还在其中存储一些关于连接的附加信息,那么这将不起作用。

我认为您应该强调,逻辑是有意向后的,因此您可以使用约束列表和.Compares(或.Contains)字段。虽然你可以用普通的方式(field.Contains(constraint_array)),但是向后的方式会产生一个更简洁的SQL查询。但我不确定是什么