2013-03-09 64 views
1

我在寻求如何更好地设计以下LINQ查询(使用WCF数据服务)的建议。要求是通过ComboBox显示员工列表。LINQ声明优化 - 寻求更好设计的建议

数据库表结构如下:

雇员可以被分配给许多项目和项目可以有很多员工。这种关系通过3个表格设计:[Employees] 1--* [EmployeeProjects] *--1 [Projects]。在dot国家,这就好像我正在遍历对象树:Employee.EmployeeProjects.Project

以下LINQ语句返回一个EmployeeProjects的列表,但是我之后是作为这些特定项目的一部分的Employee列表。理想情况下,执行IQueryable<Employee>是有意义的,但是我不知道如何构建我的LINQ语句,因为链接(很多)是EmployeeProjects。你看到我的困境吗?

我执行IQueryable<EmployeeProject>,因为从以下的LINQ语句中可以看出,我从来不必处理“Many”方面,因为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; 
} 

任何关于设计这个更好的建议将不胜感激。

回答

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

我认为你应该强调逻辑是有意向后的,以便你使用约束列表和.Compares(或.Contains)这个字段。虽然你可以按照正常的方式(field.Contains(constraint_array))来执行,但是后向方法会产生更简洁的SQL查询。 – Tory 2013-03-09 00:20:30

+0

我修正了比较 - >包含的东西,因为这是一个错字。但我不确定你的意思。 'str.Contains(arrayOfStr)'不是有效的语法。 – Corylulu 2013-03-09 00:30:08

+0

对,对不起。这就是我只需要检查某些东西而不是自己尝试的方法。我误解了一些东西,尽管它允许另一种方式(我真正阅读的内容是在另一个中调用一个LINQ to SQL查询)。我所说的其他一切仍然存在。 – Tory 2013-03-09 00:37:49

0

如果您在服务器端使用EF,您应该能够从客户端完全隐藏EmployeeProject表。 EF应该能够将你的数据库结构变成两个实体集(雇员和项目),它们之间具有多对多关系(详细地说,它将创建两个1-Many单向关系)。

因此从客户端看起来就像一个Employees实体集合,其中每个实例都有一个属性Projects,这是该员工参与的项目列表。同样,一个实体设置了Projects,其中每个实例都有一个属性Employees分配给该项目的员工名单。

接着上面的查询可以是简单得多(使用急促的URL表示法中,LINQ的版本是有点明显,也简化了项目名称的列表):

〜/项目?$ filter =(Name eq'TopX 2')或(Name eq'SiteX 32')& $ expand = Employers

这会让你得到具有指定名称的所有项目,并为每个项目分配其所有员工。

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

+0

Hello Vitek,感谢您的回复,但需要EmployeeProject类/表,因为它具有需要包含的其他属性并提供其他详细信息。这有帮助吗?谢谢... – user118190 2013-03-11 10:12:33

+0

然后正如我的答案中指出的那样,这种方法不能使用。你有什么看起来像唯一可行的方法已经。 – 2013-03-12 10:01:12

+0

感谢Vitek的回应。为了确认,尽管我想返回Employees集合,但是没有办法,因此必须首先返回一个EmployeeProjects集合?这看起来不对,就是这样。我试图寻找替代品,如使用.SelectMany(),但不知道如何按摩它到我的声明。 – user118190 2013-03-13 13:54:02