1

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

DB表结构如下:

一个员工可以分配到多个项目,一个项目可以有多个员工。这种关系是通过 3 个表设计的:[Employees] 1--* [EmployeeProjects] *--1 [Projects]. 在 dot country 中,就像我正在遍历对象树一样:Employee.EmployeeProjects.Project.

以下 LINQ 语句返回一个列表EmployeeProjects,但我所追求的是属于这些特定项目的一部分的 Employee 列表。理想情况下,执行 . 是有意义的,但由于链接(很多)IQueryable<Employee>,我不知道如何构造我的 LINQ 语句。EmployeeProjects你看到我的困境了吗?

我执行一个IQueryable<EmployeeProject>因为,正如您从下面的 LINQ 语句中看到的那样,我不必处理“许多”方面,因为 Employee 和 Project 双方都是 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还是可以简单地返回现有的?

您可以做的一件事是将字符串组合成一个数组并像这样比较它们:

//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 应该能够将您的数据库结构转换为两个实体集(员工和项目),它们之间存在多对多关系(详细地说,它将创建两个 1-Many 单向关系)。

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

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

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

这将为您提供具有指定名称的所有项目,并为每个项目提供所有分配的员工。

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

于 2013-03-09T21:47:56.253 回答