2013-08-24 3 views
4

У меня есть класс субъекта домена POCO, который содержит удобные методы для перехода к связанным записям. Я использую базу данных AdventureWorks2008R2, чтобы продемонстрировать, чего я пытаюсь выполнить. Все эти запросы можно запустить в LINQPad для наблюдения за сгенерированными операторами SQL.Запрос LINQ с использованием свойств навигации Генерирует несколько операторов SELECT

SalesOrderHeaders.Where(s => s.SalesOrderID == 43659) 
       .Single().SalesOrderDetails 

Этот оператор выдает 2 оператора SQL. Один для записи SalesOrderHeader и один для получения SalesOrderDetails. Теперь рассмотрит это утверждение, что переход к дополнительной связанной таблице:

SalesOrderHeaders.Where(s => s.SalesOrderID == 43659) 
       .Single().SalesOrderDetails.Select(s => s.SpecialOfferProduct) 

После извлечения одной записи SalesOrderHeader, класс домена будет содержать удобства свойства как это:

public IQueryable<SpecialOfferProduct> SpecialProducts 
    { 
     get 
     { 
      return SalesOrderDetails.Where(sod => sod.OrderQty > 3) 
            .Select(s => s.SpecialOfferProduct) 
            .AsQueryable(); 
     } 
    } 

Это утверждение производит несколько ЗЕЬЕСТА : по одной для каждой записи в SpecialOfferProduct. Мой вопрос: почему свойства навигации не производят одну инструкцию SELECT? Это огромная проблема с производительностью, потому что она генерирует много ненужной болтовни. Я мог бы использовать синтаксис LINQ SQL, но это только при создании исходного запроса с использованием репозитория. В этом случае у меня есть экземпляр объекта SalesOrderHeader и у меня нет доступа к Контексту или репозиторию внутри класса. Есть ли способ заставить его создать единую инструкцию SELECT с помощью JOIN?

Если это не так, я думал о создании дополнительного метода в моем репозитории для заполнения этих свойств. Проблема в том, что у меня есть 2 шага: 1 для извлечения объекта SalesOrderHeader, а затем для заполнения дополнительных свойств с помощью соответствующего оператора LINQ, который заставит синтаксис JOIN.

+1

У вас установлена ​​ленивая загрузка. Установите значение false или используйте метод «Include», чтобы активно загружать объекты свойств навигации. – MarcinJuraszek

ответ

2

Как сказано в комментарии вам нужно Include метод:

SalesOrderHeaders.Include(s => s.SalesOrderDetails 
           .Select(d => d.SpecialOfferProduct)) 
       .Where(s => s.SalesOrderID == 43659) 
       .Single().SalesOrderDetails 

это присоединиться необходимые данные (в SQL) и заселить навигационные свойства.

Заметим, однако, что вы не можете использовать синтаксис как

.Include(s => s.SalesOrderDetails.Where(sod => sod.OrderQty > 3) 
       .Select(d => d.SpecialOfferProduct)) 

Что, казалось бы, было бы частично заполнить SalesOrderDetails. Запросы на изменение в команде EF для этого, но до сих пор это не было сделано.

Еще одно замечание состоит в том, что бесполезно возвращать SpecialProducts как IQueryable, потому что последующие запросы в коллекции в любом случае не будут переведены на SQL. Вы можете получить доступ к свойству только в операциях внутри памяти, а не в запросах linq-to-enitites (EF cant переводит свойство в SQL).

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