2017-02-08 5 views
0

Моя модель:Как факторизовать запрос Linq с несколькими включенными?

  • Несколько DeviceStatus прилагается к один обязательный Device
  • Несколько Device прилагается к один обязательный Panel

Когда я запрашиваю DeviceStatus, мне нужно иметь Device и Panel прилагается к нему в результате запроса.

... DeviceStatus.Device имеет значение null в результате запроса.

Вот Linq запрос:

using (var actiContext = new ActigraphyContext()) 
{ 
    var todayStatus = 
     from s in actiContext.DeviceStatus.Include(s1 => s1.Device.Panel) 
     where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime(DateTimeOffset.Now) 
       && s.Device.Panel.Mac == mac 
       && (s.Device.Ty == 4 || s.Device.Ty == 9) 
     select s; 

    // var tempList = todayStatus.toList(); 

    var todayLastStatus = 
     from s in todayStatus.Include(s1 => s1.Device.Panel) 
     let lastTimeStamp = todayStatus.Max(s1 => s1.TimeStamp) 
     where s.TimeStamp == lastTimeStamp 
     select s; 

    var requestResult = todayLastStatus.FirstOrDefault(); 

    return requestResult; 
} 

Если я раскомментировать строку // var tempList = todayStatus.toList();, где TempList не используется, он работает: requestResult.Device установлен! Но плохая сторона todayStatus.toList запускает запрос, который приносит огромный объем данных.

Как получить DeviceStatus с его относительными объектами?

Примечание: база данных за это SQL Server 2012

ответ

2

при вызове Include() по запросу LINQ, он выполняет Жадно Загрузку.

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

Чтобы завершить выполнение запроса, вам нужно вызвать .toList().

Поскольку данные огромны, вы можете выбирать соответствующие столбцы в соответствии с вашими требованиями, используя предложение Select.

var todayStatus = 
    from s in actiContext.DeviceStatus 
    .Include(s1 => s1.Device.Panel.Select(d => new 
              { 
               d.DeviceId, 
               d.DeviceName, 
               d.PanelID 
              })) 
    where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime(DateTimeOffset.Now) 
      && s.Device.Panel.Mac == mac 
      && (s.Device.Ty == 4 || s.Device.Ty == 9) 
    select s; 

var tempList = todayStatus.toList(); 
+0

Мне нужно вернуть только один элемент с todayLastStatus.FirstOrDefault(), слишком много todayStatus для выполнения todayStatus.toList(), и мне нужны все свойства obejcts. – abreneliere

+0

Не проблема. Вместо вызова .toList(), вызовите .FirstOrDefault() на todayStatus. Я обновил запрос Select. Вы можете получить ограниченное количество столбцов, чтобы сохранить ваши потребности на месте. – RRM

+0

Мне не нужен первый, мне нужен один с lastTimeStamp, поэтому я выполняю let lastTimeStamp = todayStatusForMax.Max (s1 => s1.TimeStamp) – abreneliere

-1

Запрос на самом деле не работать, пока вы не сделаете вызов, как ToList(), поэтому раскомментировав работает эта линия. Если запрос возвращает слишком много данных, вам нужно изменить запрос, чтобы сузить количество данных, которые вы возвращаете.

+1

Я уже знаю это: как подключить устройства и панели к состоянию без запуска todayStatus запрос? – abreneliere

+0

Извините, я неправильно понял ваш вопрос. – Freakshow

0

Ok этот запрос является более простым способом для достижения этой цели:

 using (var actiContext = new ActigraphyContext()) 
     { 
      var todayLastStatus = 
       from s in actiContext.DeviceStatus.Include(s1 => s1.Device.Panel) 
       where DbFunctions.TruncateTime(s.TimeStamp) == DbFunctions.TruncateTime(DateTimeOffset.Now) 
         && s.Device.Panel.Mac == mac 
         && (s.Device.Ty == 4 || s.Device.Ty == 9) 
       orderby s.TimeStamp descending 
       select s; 

      var requestResult = todayLastStatus.Take(1).FirstOrDefault(); 

      return requestResult; 
     } 

Но остается вопрос: почему я не получаю относительный объект в моем первом запросе?