2

我有一些简单的代码可以从数据库中检索记录的 ELMAH 异常:

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>。鉴于此,为什么我不在我的投影中使用 Linq-To-Objects API,它理解AddHours(),而不是仍然使用 Linq-To-Entities API?

更新

Jon Skeet 在这里有一篇关于这个主题的帖子:

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 异常,我以为我会针对 Linq-To-Objects API 执行。

进一步更新

来自 Jim Wooley 的博客: http: //linqinaction.net/blogs/jwooley/archive/2009/01/21/linq-supported-data-types-and-functions.aspx

“例如,以下方法显示为具有 DateTime 值的转换:Add、Equals、CompareTo、Date、Day、Month、Year。相反,不支持 ToShortDateString、IsLeapYear、ToUniversalTime 等方法。

如果您需要使用其中一种不受支持的方法,则需要将结果强制发送给客户端并在此时使用 LINQ to Objects 评估它们。您可以在查询理解的任何时候使用 .AsEnumerable 扩展方法来做到这一点。”

这不是我在做什么吗?

4

1 回答 1

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();
于 2013-11-07T13:43:07.997 回答