Как избежать больших сгенерированных SQL-запросов в EF при использовании Include()

Я использую EF (версия dll 4.4) для запроса к базе данных. База данных содержит несколько таблиц с информацией о курсе. Когда вы посмотрите, что на самом деле отправлено в db, я вижу массивный, почти 1300 строк SQL-запрос (который я не собираюсь вставлять здесь из-за его размера). Запрос, который я запускаю в контексте, выглядит следующим образом:

entities.Plans
  .Include("program")
  .Include("program.offers")
  .Include("program.fees")
  .Include("program.intakes")
  .Include("program.requirements")
  .Include("program.codes")
  .Include("focuses")
  .Include("codes")
  .Include("exceptions")
  .Include("requirements")
where plans.Code == planCode
select plans).SingleOrDefault(); 

Я хочу избежать необходимости возвращаться на сервер при сборе информации из каждой из связанных таблиц, но с таким большим запросом мне интересно, есть ли лучший способ сделать это?

Спасибо.

Ответ 1

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

Ответ 2

Обычно вы можете добавить .Include() после предложения where. Это означает, что вы вынимаете только информацию, которая соответствует тому, что вы хотите, посмотрите, не уменьшит ли ваш запрос какой-либо.

Ответ 3

Как вы выполняете активную загрузку, поэтому, если вы выбираете требуемые объекты, то это нормально. В противном случае вы можете пойти с Lazy Loading, но поскольку вы указали, что вам не нужна база данных в оба конца, вы можете ее избежать.

Я бы предположил, что если этот запрос используется несколько раз, вы можете использовать скомпилированный запрос. Чтобы повысить производительность,

Пройдите по этой ссылке, если хотите..  http://msdn.microsoft.com/en-us/library/bb896297.aspx

Ответ 4

Если вы используете DbContext, вы можете использовать свойство .Local в контексте, чтобы посмотреть, уже ли ваш объект уже извлечен и поэтому привязан к контексту.

Если запрос выполнялся раньше, и ваши корневые объекты Plan уже привязаны на основе Plan.Code == planId, предположительно его суб-сущности также уже прикреплены, так как вы действительно загружаете загрузку, поэтому ссылайтесь на них через свойства навигации, t поражает БД для них снова в течение жизни этого контекста.

Эта статья может оказаться полезной при использовании .Local.

Ответ 5

Возможно, вы сможете получить чуть более сжатый SQL-запрос, используя прогноз, а не Include, чтобы отбросить ваши ссылочные объекты:

var planAggregate = 
 (from plan in entities.Plans
  let program = plan.Program
  let offers = program.Offers
  let fees = program.Fees
  //...
  where plan.Code == planCode
  select new {
    plan
    program,
    offers,
    fees,
    //...
  })
  .SingleOrDefault();

Если вы отключите ленивую загрузку в своем контексте, такой запрос приведет к тому, что свойства навигации ваших объектов будут заполнены объектами, включенными в ваш запрос.

(Я тестировал это только на EF.dll v5.0, но он должен вести себя одинаково на EF.dll v4.4, который является только EF5 на .NET 4.0. Когда я тестировал этот шаблон, а не Include в запросе аналогичной формы он вырезает около 70 строк из 500 строк SQL. Ваш пробег может отличаться.)