c# - 对象函数在 LINQ to Entities 表达式中失败

标签 c# sql linq linq-to-entities

请注意:我知道如何解决这个问题。我不是在寻找解决方案,我是在寻找问题本身的清晰度。

class Program
{
    static void Main(string[] args)
    {
        using (var context = new TestDbContext())
        {
            var eventsFound = context.Events
                .Where(e => 
                    e.EventDate >= DateTime.Now.AddDays(-1) && 
                    e.EventDate <= DateTime.Now.AddDays(+1)
                )
                .ToList();
        }
    }
}

public class TestDbContext : DbContext
{
    public DbSet<Event> Events { get; set; }
}

public class Event
{
    public int EventId { get; set; }
    public DateTime EventDate { get; set; }
}

好的,所以上面的程序失败了:

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

为什么 LINQ 不能区分数据库函数和对象函数。系统应该足够聪明,可以意识到 AddDays 函数是 DateTime 对象的一部分。然后它应该首先解析该函数​​,然后在解析查询中的所有函数后,转换为 SQL 并针对数据库执行。

我敢肯定它比这复杂得多,但我想了解原因。

========= 编辑 ==============

所以上面的例子实际上并不是一个很好的例子,因为“AddDays”是一个同时存在于 .NET 和 SQL 中的函数。当我将它更改为一个不存在歧义的自定义函数时会怎么样。

即:

public class Event
{
    public int EventId { get; set; }
    public DateTime EventDate { get; set; }

    public DateTime ReturnDateNowExample()
    {
        return DateTime.Now;
    }
}

static void Main(string[] args)
{
    var myEvent = new Event {EventDate = new DateTime(2013, 08, 28)};
    using (var context = new TestDbContext())
    {
        var eventsFound = context.Events
            .Where(e =>
                e.EventDate >= myEvent.ReturnDateNowExample()
            )
            .ToList();
    }
}

如果是不明确的 DateTime 对象,则用 string/int 对象替换。

最佳答案

这样做的原因与其“聪明”无关,更多的是与 Linq 的工作方式有关。 Linq 使用一种称为“表达式树”的东西。基本上,它将您的表达式编译为一组数据,然后由翻译层将其转换为 SQL。

这不起作用的原因是因为这是在 where 子句中,where 子句必须在 SQL 中执行才能准确。它不能在后端的 C# 代码中执行,至少不能在没有静默返回表的所有行的情况下执行,这不是所需的功能......如果是,您可以告诉它明确地执行此操作。

Entity Framework 提供了一组用于处理日期的函数,这些函数可以直接转换为 SQL,这些函数位于 EntityFunctions 命名空间中。这些映射到所谓的“规范函数”,这意味着对 SQL 有 1:1 的翻译。 Linq to Sql 将客户端评估的 where 子句作为参数传递,但这可能是也可能不是所需的值,因为您可能需要服务器端值而不是客户端计算值。因此 L2S 会给您意想不到的结果在某些情况下会产生结果。

简单地说,您需要特殊的表达式函数才能转换为 SQL,不幸的是,任何旧的标准 .NET 类都不起作用,DateTime 类就是这样。

您可能会发现以下文章很有用:

http://blogs.msdn.com/b/charlie/archive/2008/01/31/expression-tree-basics.aspx

http://tomasp.net/blog/linq-expand.aspx/

http://social.msdn.microsoft.com/Forums/en-US/21a9c660-13e5-4751-aa51-6519bddae044/enterprise-framework-linq-queries-failing

关于c# - 对象函数在 LINQ to Entities 表达式中失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18482248/

相关文章:

c# - Linq 处理可变数量的 OrderBy

c# - C# 中的通用 foreach 循环

mysql - 元 key :value fields returning NULL

linq - 如何快速查找 List<T> 中的重复项,并更新原始集合

c# - Linq 在同一个列表中添加相同的项目

c# - Contains() 返回 false,即使它应该返回 true

c# - 使用 C# 进行文件压缩的​​最佳方法

php - 如何修改此 PHP 查询以添加数据库值 'timestamp'?

sql - Mysql中索引的奇怪使用

c# - 关闭 WPF MVVM 中的窗口