2016-04-21 2 views
3

Попытка реализовать условные выражения в запросе LINQ (с Entityframework) создает странные запросы. В некоторых случаях эти запросы времени, даже если порог установлен на 180 секунд:Условие LINQ to Entities дает странные результаты

   List<LogEntity> dataList = db.LogEntities.Where(x => 
       x.Source == "Source" && 
       (String.IsNullOrEmpty(from) || x.EventDate >= cFrom) && 
       (String.IsNullOrEmpty(to) || x.EventDate <= cTo) && 
       (String.IsNullOrEmpty(uid) || x.DomainUserLogin == uid) && 
       (String.IsNullOrEmpty(cid) || x.CaseReference == cid) && 
       (String.IsNullOrEmpty(searchtext) || x.Message.Contains(searchtext))) 
       .OrderByDescending(y => y.EventDate) 
       .Take(500) 
       .ToList<LogEntity>(); 

с несколько менее элегантно, если-заявления, я не получаю никаких проблем, а запросы возвращают через несколько секунд:

   IQueryable<LogEntity> data = db.LogEntities.Where(x => x.Source == "Source"); 
      if (!String.IsNullOrEmpty(from)) 
       data = data.Where(x => x.EventDate >= cFrom); 
      if (!String.IsNullOrEmpty(to)) 
       data = data.Where(x => x.EventDate <= cTo); 
      if (!String.IsNullOrEmpty(uid)) 
       data = data.Where(x => x.DomainUserLogin == uid); 
      if (!String.IsNullOrEmpty(cid)) 
       data = data.Where(x => x.CaseReference == cid); 
      if (!String.IsNullOrEmpty(searchtext)) 
       data = data.Where(x => x.Message.Contains(searchtext)); 
      data = data.OrderByDescending(x => x.EventDate).Take(500); 
      List<LogEntity> dataList = data.ToList<LogEntity>(); 

Условные все передаются из строки запроса, поэтому они иногда могут нести значение, а иногда нет.

Та же проблема возникает при использовании трехкомпонентных операторов как

...Where(x => truth ? x.something == somevalue : x.something == anothervalue) 

Есть ли какое-то разумное объяснение, почему эти встроенные условные выполнять так плохо?

+4

Текущий переводчик EF запрос не уменьшает постоянные выражения. Не тратьте впустую свое время, стиль 'if' - это правильный путь. –

+0

Я передумал. Ваш вопрос (наряду с некоторыми другими) заставил меня начать думать об общем решении. посмотрите на мой ответ на [«Исключительный объект должен иметь значение» исключение после проверки на null на объекте non-primitive/non-struct] (http://stackoverflow.com/questions/36892232/nullable-object-must- есть-а-значение- exception-after-check-for-null-on-a-non-p/36896900 # 36896900) и посмотреть, работает ли для вас метод пользовательских расширений. –

ответ

2

Когда вы пишете запросы с LINQ в EF-базах данных, они выглядят очень естественно, но за сценой есть переводчик запросов, который анализирует ваш запрос LINQ и разбивает его на 2 части: один выполняется на сервере sql, другой - на клиенте используя только расширения LINQ.

При использовании некоторого выражения, которое переводчик запросов не может перевести на SQL (например, некоторые функции .NET), он минимизирует фильтрацию данных, и в итоге вы можете загрузить всю таблицу данных клиенту и отфильтровать его.

В первом запросе, который вы написали, вы используете (String.IsNullOrEmpty(from) || x.EventDate >= cFrom); «from» является внешним по отношению к LogEntities, и переводчик не может делать никаких предположений о его значениях и о том, как он рассчитывается в отношении записей. Таким образом, скорее всего, вы просто загружаете полный клик на клиенте и фильтруете его клиенту. Если количество записей велико, вы получите ошибку тайм-аута.

Во втором запросе вы присоединились к простым выражениям Where(x => x.DomainUserLogin == uid);, которые явно переведены на sql. Таким образом, вы получаете правильный SQL-запрос, который фильтрует большинство записей на стороне сервера sql.

Вы можете использовать SQL Profiler, или VS инструменты (в зависимости от VS изданий, или включение входа в EF, чтобы увидеть фактический запрос, выполняются.

There's some information on MSDN

+0

Спасибо за это объяснение, однако я бы предположил, что операторы C# должны быть оценены перед передачей на переводчик запросов. Очевидно, это не так, поэтому я воздержусь от их использования так. – Niklas

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