Лямбда-синтаксис для объединений через свойство навигации?

1

Я могу выполнить соединение, используя свойство навигации, которое для меня более DRY, потому что я не повторяю критерии соединения везде:

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

Поскольку ORM знает, как компании связаны с сотрудниками, c.Employees навигации c.Employees используется для определения критериев FK для соединения.

Что такое прямой перевод на расширение/лямбда-синтаксис множественного предложения из свойства навигации?

Я знаю, что существует метод расширения Объединения, но требует, чтобы вы явно указывали, что 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 это намного проще, потому что у вас есть c, e и v все в контексте выбора. Я не знаю, можете ли вы выразить одно и то же в методах расширения, так что все три псевдонима/ссылки передаются вниз. Возможно, это просто следствие синтаксиса метода расширения, но надеясь, что кто-то предоставит лучший эквивалент.

Теги:
linq

2 ответа

4
Лучший ответ

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

См. Это сообщение в блоге для более подробной информации и подробного описания этого преобразования и того, как он масштабируется.

4

Разве это не было бы чем-то вроде:

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

Поскольку у каждого сотрудника есть Компания, почему бы просто не добавить навигационное свойство "Компания" в компанию Employee?

Чтобы получить отпуск, просто измените его на следующее:

 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
    У него есть свойство навигации в Employee for Company . это то, что он использует. Он пытается использовать его, чтобы спроецировать свой запрос на коллекцию пар сотрудника и компании. Он делает это прекрасно, используя синтаксис запроса, но не делает этого, используя синтаксис метода. Вы не смоделировали этот синтаксический запрос в этом ответе.
  • 0
    Это именно то, что делает мой запрос. Я указал синтаксис метода, просто другой подход. EF выполнит правильное соединение, как и при выполнении запроса.
Показать ещё 3 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню