2013-11-07 11 views
2

У меня есть простой код, который извлекает записанные исключения Elmah из БД:NotSupportedException выброшен после вызова .AsEnumerable()

HealthMonitoringEntities context = new HealthMonitoringEntities(); 
IQueryable<ELMAH_Error> exceptions = context.ELMAH_Error; 

if (filter.ToDate != null) 
    exceptions = exceptions.Where(e => e.TimeUtc <= filter.ToDate.Value.AddHours(-4)); 

return exceptions.OrderByDescending(e => e.TimeUtc) 
    .Take(filter.Size) 
    .AsEnumerable() 
    .Select(e => new ElmahException() 
    { 
     ErrorId = e.ErrorId, 
     Application = e.Application, 
     Host = e.Host, 
     Type = e.Type, 
     Source = e.Source, 
     Error = e.Message, 
     User = e.User, 
     Code = e.StatusCode, 
     TimeStamp = e.TimeUtc.AddHours(-4).ToString() 
    }).ToList(); 

    } 

я получаю исключение на этой линии:

TimeStamp = e.TimeUtc.AddHours(-4).ToString() 

Исключением является:

LINQ to Entities does not recognize the method 'System.DateTime AddHours(Double)' method, and this method cannot be translated into a store expression. 

Когда я звоню .AsEnumerable() перед началом проекции с Select(), моя последовательность перечисляется, и я проецируюсь из последовательности, которая реализует IEnumerable<ELMAH_Error>. Учитывая это, почему я не работаю с API Linq-To-Objects в моей проекции, который понимает AddHours(), а не работает с API Linq-To-Entities?

UPDATE

Существует пост на эту тему Джон тарелочкам здесь:

http://msmvps.com/blogs/jon_skeet/archive/2011/01/14/reimplementing-linq-to-objects-part-36-asenumerable.aspx

Он имеет этот запрос:

var query = db.Context 
      .Customers 
      .Where(c => some filter for SQL) 
      .OrderBy(c => some ordering for SQL) 
      .Select(c => some projection for SQL) 
      .AsEnumerable() // Switch to "in-process" for rest of query 
      .Where(c => some extra LINQ to Objects filtering) 
      .Select(c => some extra LINQ to Objects projection); 

Обратите внимание, что после его вызова AsEnumerable(), он указал, что переключается на Linq-To-Objects. Я выполняю что-то подобное в своей функции, но получаю исключение Linq-To-Entities, где я думал, что буду выполнять API Linq-To-Objects.

Дальнейшее обновление

Из блога Джима Вули в: http://linqinaction.net/blogs/jwooley/archive/2009/01/21/linq-supported-data-types-and-functions.aspx

«В качестве примера следующие методы показаны как имеющие переводы для значений DateTime: Добавить, Равно, CompareTo, дата, день, месяц, В отличие от методов, таких как ToShortDateString, IsLeapYear, ToUniversalTime не поддерживаются.

Если вам нужно использовать один из неподдерживаемых методов, вам нужно принудительно выполнить результаты для клиента и просчитать их, используя LINQ to Objects в этой точке.Это можно сделать с помощью метода расширения .AsEnumerable в любой точке понимания запроса. "

Разве это не то, что я делаю?

+0

Расширения AsEnumerable() из Queryable не будет перечислять. Он возвращает только IEnumarable . – Jehof

ответ

0

Вы забыли защитить свой первый вызов

if (filter.ToDate != null) 
    exceptions = exceptions.AsEnumerable() 
          .Where(e => e.TimeUtc <= filter.ToDate.Value.AddHours(-4)); 

Редактировать Помните, IQueryables не переведены на SQL, пока они не будут перечислены, так что ваш отладчик будет выполнять эту строку, но ошибка не будет происходить пока вы не вернетесь. Если filter.ToDate является нулевым код эквивалентен следующему: метод

if(filter.ToDate == null) 
    return exceptions 
     .Where(e => e.TimeUtc <= filter.ToDate 
            .Value 
            .AddHours(-4)) //uh-oh won't work in Linq-to-Entities 
            .OrderByDescending(e => e.TimeUtc) 
     .Take(filter.Size) 
     .AsEnumerable() //too late to protect you! 
     .Select(e => new ElmahException() 
     { 
      ErrorId = e.ErrorId, 
      Application = e.Application, 
      Host = e.Host, 
      Type = e.Type, 
      Source = e.Source, 
      Error = e.Message, 
      User = e.User, 
      Code = e.StatusCode, 
      TimeStamp = e.TimeUtc.AddHours(-4).ToString() //if we get this far we're OK 
     }).ToList(); 
+0

Эта строка не вызывает проблемы, дата разрешается до передачи провайдеру. –

+0

Я не уверен, что вы подразумеваете под «дата разрешена до передачи провайдеру», но если «фильтр».ToDate' имеет значение null, тогда вы получите сообщение об ошибке. Я добавил больше объяснений – Colin

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