通过导航属性连接的Lambda语法?

时间:2015-04-02 19:43:30

标签: c# linq

我可以使用导航属性执行连接,这对我来说更干,因为我没有在任何地方重复连接标准:

(from c in db.Companies
from e in c.Employees
select new { Employee = e, Company = c}).ToList();

由于ORM知道公司与员工的关系,c.Employees导航属性用于推断加入的FK标准。

通过导航属性直接转换为from from子句的扩展/ lambda语法是什么?

我知道有一个Join扩展方法,但是要求你明确命名要比较的FK,而不是它暗示导航属性的标准。这是不行的,但希望表达我的意图:

db.Companies
  .Join(c.Employees, /* don't want to explicitly name FKs*/)
  .Select(x => new { Employee = x.e, Company = x.c}).ToList();

当然Join(c.Employees不起作用,因为在此上下文中没有c,但想法以某种方式使用Companies.Employees导航属性来暗示连接条件。

我知道我能做到:

db.Companies.Select(c => new { Employees = c.Employees, Company = c })

但这是一个不同的结果集,因为它为每个公司返回一条记录,然后将雇员列表作为嵌套属性。而不是第一个是连接,因此每个相关组合都有一个记录,结果具有Employee属性而不是Employees集合。

我不确定,但猜测.SelectMany是直接翻译。您没有获得对父项的c引用,因此如果您执行以下操作中的多项:

db.Companies.SelectMany(c=>c.Employees).SelectMany(e=>e.VacationDays).Select(v => new { VacationDay = v, Employee = v.Employee, Company = v.Employee.Company })

你必须在这些关系中向后走,才能使联接变得平坦。在linq中,它更简单,因为在select的上下文中你会cev。我不知道你是否可以在扩展方法中表达相同的东西,这样就传递了所有三个别名/引用。也许只是扩展方法语法的结果,但希望有人能提供更好的等价物。

2 个答案:

答案 0 :(得分:5)

不会只是这样:

db.Employees.Select(m => new { Employee = m, Company = m.Company });

由于每位员工都有公司,为什么不将导航属性“公司”添加到员工实体?

要获得假期,只需将其更改为以下内容:

 db.Employees.SelectMany(
 employee => employee.VacationDays, 
 (employee, vacationDay) => new 
  { 
      Employee = employee, 
      Company = employee.Company, 
      VacationDay = vacationDay 
  });

更新

实际上,之间没有区别:

(from c in db.Companies
 from e in c.Employees
 select new { Employee = e, Company = c}).ToList();

(from e in c.Employees
 from c in db.Companies
 select new { Employee = e, Company = c}).ToList();

答案 1 :(得分:5)

SelectMany确实是多个from子句被映射到的内容。

为了将变量保留在范围内,每个SelectMany需要将序列投影到一个新的匿名对象中,该对象将所有适当的变量保留在范围内:

var query = db.Companies.SelectMany(company => company.Employees, 
    (company, employee) => new
{
    company,
    employee
});

要为其他嵌套导航属性添加其他投影,只需重复该模式,然后调用SelectMany

var query = db.Companies.SelectMany(company => company.Employees,
    (company, employee) => new
{
    company,
    employee
}).SelectMany(pair => pair.employee.VacationDays,
    (pair, vactionDay) => new
{
    pair.company,
    pair.employee,
    vactionDay,
});

请参阅this blog post以获取更多详细信息以及对此转换的深入描述,以及它如何扩展。