2012-01-25 4 views
4

Рассмотрим следующий запрос:Linq To Entities Query

var profilelst = 
    (
     from i in dbContext.ProspectProfiles 
     where i.CreateId == currentUser 
     select new ProspectProfile 
     { 
      ProspectId = i.ProspectId, 
      Live = i.Live, 
      Name = i.Name, 
      ServiceETA = i.Opportunities.OrderByDescending(t => t.FollowUpDate) 
       .FirstOrDefault() 
       .ServiceETA.ToString(), 
      FollowUpDate = i.Opportunities.OrderByDescending(t => t.FollowUpDate) 
       .FirstOrDefault() 
       .FollowUpDate 
     } 
    ) 
    .ToList(); 

return profilelst.OrderByDescending(c=>c.FollowUpDate) 
     .Skip(0).Take(endIndex) 
     .ToList(); 

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

Один к многим в таблицах, как: ProspectProfile -> Opportunities

ли запрос я написал это нормально или есть какая-то другая работа вокруг этого можно сделать проще.

+0

Переформатированный код, чтобы сделать его доступным для чтения, однако фактический вопрос не ясен. –

+0

Вы проверили, работает ли ваш первый запрос вообще? У меня есть сомнения. – Slauma

ответ

4

Единственное, что вы можете улучшить, чтобы избежать заказа дважды, изменив свой код следующим образом:

var profilelst 
    = dbContext.ProspectProfiles 
      .Where(i => i.CreateId == currentUser) 
      .Select(i => 
        { 
         var opportunity 
          = i.Opportunities 
           .OrderByDescending(t => t.FollowUpDate) 
           .First(); 
         return new ProspectProfile 
         { 
          ProspectId = i.ProspectId, 
          Live = i.Live, 
          Name = i.Name, 
          ServiceETA = opportunity.ServiceETA.ToString(), 
          FollowUpDate = opportunity.FollowUpDate 
         } 
        }).ToList(); 

return profilelst.OrderByDescending(c => c.FollowUpDate).Take(endIndex).ToList(); 

Я сделал несколько изменений в исходном запросе:

  1. Я изменил его использовать метод синтаксис цепей. По-моему, читать гораздо проще.
  2. Я удалил ненужный Skip(0).
  3. Самое большое изменение в Select части:
    1. Я изменил FirstOrDefault к First, потому что вы доступа к свойствам возвращаемого значения в любом случае. Это вызовет описательное исключение, если нет возможности. Это лучше, чем то, что у вас было: в вашем случае это бросит NullReferenceException. Это плохо, NullReferenceExceptions всегда указывают на ошибку в вашей программе и не описывают ее вообще.
    2. Я переместил часть, которая выбирает возможность из инициализатора, поэтому нам нужно делать сортировку только один раз, а не дважды.
+0

+1 для исключения NullReference – ken2k

+0

Я не думаю, что это будет работать с LINQ to Entities, потому что проецирование в сущность не поддерживается, 'First()' не поддерживается в проекции, и я сомневаюсь, что использование локальной переменной в выражение 'Select' поддерживается. – Slauma

+0

@Slauma: Хорошая точка. Позаботьтесь о предоставлении альтернативного решения? –

1

Есть немало проблем в вашем запросе:

  • Вы не можете проецировать в юридическое лицо (select new ProspectProfile). LINQ к Entities поддерживает только проекции в анонимные типы (select new) или другие типы, которые не являются частью вашей модели (select new MySpecialType)

  • ToString() объекта данных для числового или DateTime типа не поддерживается в LINQ к Entities (ServiceETA.ToString())

  • FirstOrDefault().ServiceETA (или FollowUpdate) сгенерирует исключение, если Opportunities коллекция пуста и ServiceETA является типом ненулевого значения (например, DateTime), потому что EF не может материализовать любое значение в такой переменный.

  • Используя .ToList() после того, как ваш первый запрос выполнит запрос в базе данных и загрузит полный результат. Ваш более поздний Take происходит в памяти в полном списке, а не в базе данных. (Вы эффективно загружаете весь список результатов из базы данных в память и затем выбрасываете все объекты, кроме первого, у вас есть Take ru.

Чтобы решить все четыре проблемы, которые Вы можете попробовать следующее:

var profilelst = dbContext.ProspectProfiles 
    .Where(p => p.CreateId == currentUser) 
    .Select(p => new 
    { 
     ProspectId = p.ProspectId, 
     Live = p.Live, 
     Name = p.Name, 
     LastOpportunity = p.Opportunities 
      .OrderByDescending(o => o.FollowUpDate) 
      .Select(o => new 
      { 
       ServiceETA = o.ServiceETA, 
       FollowUpDate = o.FollowUpDate 
      }) 
      .FirstOrDefault() 
    }) 
    .OrderByDescending(x => x.LastOpportunity.FollowUpDate) 
    .Skip(startIndex) // can be removed if startIndex is 0 
    .Take(endIndex) 
    .ToList(); 

Это даст вам список анонимных объектов. Если вам нужен результат в списке вашего объекта ProspectProfile, вы должны скопировать значения после этого запроса. Обратите внимание, что LastOpportunity может быть null в результате, если ProspectProfile не имеет Opportunities.