2010-07-28 4 views
131

Это может быть действительно элементарный вопрос, но какой хороший способ включить несколько дочерних объектов при написании запроса, который охватывает три уровня (или более)?Entity framework linq query Включить() несколько дочерних объектов

т.е. у меня есть 4 таблицы: Company, Employee, Employee_Car и Employee_Country

Компания имеет 1 а: М отношения с работника.

Сотрудник имеет отношения 1: m с Employee_Car и Employee_Country.

Если я хочу написать запрос, который возвращает данные из всех 4 таблиц, я в настоящее время пишу:

Company company = context.Companies 
         .Include("Employee.Employee_Car") 
         .Include("Employee.Employee_Country") 
         .FirstOrDefault(c => c.Id == companyID); 

Там должна быть более элегантным способом! Это долго наматывается и создает ужасающую SQL

Я использую EF4 с VS 2010

ответ

163

Использование extension methods. Заменить NameOfContext с названием вашего контекста объекта.

public static class Extensions{ 
    public static IQueryable<Company> CompleteCompanies(this NameOfContext context){ 
     return context.Companies 
      .Include("Employee.Employee_Car") 
      .Include("Employee.Employee_Country") ; 
    } 

    public static Company CompanyById(this NameOfContext context, int companyID){ 
     return context.Companies 
      .Include("Employee.Employee_Car") 
      .Include("Employee.Employee_Country") 
      .FirstOrDefault(c => c.Id == companyID) ; 
     } 

} 

Тогда ваш код становится

 Company company = 
      context.CompleteCompanies().FirstOrDefault(c => c.Id == companyID); 

    //or if you want even more 
    Company company = 
      context.CompanyById(companyID); 
+5

Это замечательно. –

+0

Но я хотел бы использовать его в этом, как: '// внутри общественных расширений статических классов общественных статического IQueryable CompleteCompanies (это DbSet таблица) { возвращение таблицы .INCLUDE («Employee.Employee_Car») .INCLUDE (» Employee.Employee_Country "); } // код будет ... Компания компании = context.Companies.CompleteCompanies(). FirstOrDefault (c => c.Id == companyID); // тот же для следующего продвинутого метода – Hamid

+0

Bullsye Nix. Расширения должны быть первым портом вызова для ... ну ... расширения предопределенных функциональных возможностей. – ComeIn

24

Вы можете найти эту статью интерес, который доступен на codeplex.com.

В статье представлен новый способ выражения запросов, которые охватывают несколько таблиц в форме декларативных форм графа.

Кроме того, статья содержит тщательное сравнение производительности этого нового подхода с запросами EF. Этот анализ показывает, что GBQ быстро превзошел запросы EF.

+1

Очень интересная статья! –

91

EF 4,1 до EF 6

Существует strongly typed .Include, который позволяет требуемую глубину нетерпеливого нагрузки, указываемые при условии Выберите выражения соответствующей глубины:

using System.Data.Entity; // NB! 

var company = context.Companies 
        .Include(co => co.Employees.Select(emp => emp.Employee_Car)) 
        .Include(co => co.Employees.Select(emp => emp.Employee_Country)) 
        .FirstOrDefault(co => co.companyID == companyID); 

СКП генерируемой в оба экземпляра по-прежнему никоим образом не интуитивно понятны, но кажутся достаточно совершенными.Я положил небольшой пример на GitHub here

EF Ядра

EF Ядро имеет новый метод расширения, .ThenInclude(), хотя синтаксис slightly different:

var company = context.Companies 
        .Include(co => co.Employees) 
          .ThenInclude(emp => emp.Employee_Car) 
         ... 

В соответствии с Документами, я сохранит дополнительный «отступ» в .ThenInclude, чтобы сохранить ваше здравомыслие.

Устаревшая информация (Не делайте этого):

Множественные внуков Загрузка может быть сделано за один шаг, но это требует довольно неудобный разворот обратно на графике перед заголовком следующего узла (NB: Это не работает с AsNoTracking() - вы получите сообщение об ошибке во время выполнения):

var company = context.Companies 
     .Include(co => 
      co.Employees 
       .Select(emp => emp.Employee_Car 
        .Select(ec => ec.Employee) 
        .Select(emp2 => emp2.Employee_Country))) 
     .FirstOrDefault(co => co.companyID == companyID); 

Так что я хотел бы остаться с первым вариантом (один Включать на лист объекта глубины модели).

+3

Мне было интересно, как это сделать с помощью строго типизированных. Включайте утверждения. Проецирование детей с помощью Select было ответом! – 2015-05-13 13:19:13

+6

Спасибо за добавление пространства имен !!! – GRGodoi

+1

Мой эквив «co.Employees.Select (...)» показывает синтаксическую ошибку в «Выбрать», говоря, что «« Сотрудники »не содержат определения для« Выбрать »[или метод расширения]». Я включил System.Data.Entity. Я хочу получить только один столбец из объединенной таблицы. –

Смежные вопросы