【问题标题】:why is LINQ to SQL tricked by an extension method? what now?为什么 LINQ to SQL 会被扩展方法欺骗?现在怎么办?
【发布时间】:2010-10-11 05:02:27
【问题描述】:

考虑我的Event 类,我将DateTime 存储在数据库中作为UTC 日期。我只是想根据特定时区的当前日期返回过滤范围 - 很简单吧?

这很好用:

IQueryable<Event> test1 = this.GetSortedEvents().Where(e => e.FinishDateTime.Date >= DateTime.UtcNow.Date);

这也很好用:

IQueryable<Event> test2 = this.GetSortedEvents().Where(e => e.FinishDateTime.AddHours(3).Date >= DateTime.UtcNow.AddHours(3).Date);

.. 并且还符合我的时区要求。

所以在这里我想我可以将这个特定的转换移到这个扩展方法中:

    public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
    {
        return utcTime.AddHours(3);
    }

这不起作用:

IQueryable<Event> test3 = this.GetSortedEvents().Where(e => e.FinishDateTime.RiyadhTimeFromUtc().Date >= DateTime.UtcNow.RiyadhTimeFromUtc().Date);

.. 我得到这个 NotSupportedException: Method 'System.DateTime RiyadhTimeFromUtc(System.DateTime)' has no supported translation to SQL.

这显然是垃圾,因为当扩展方法中没有相同的代码时,编译器很乐意将其转换为 SQL。

我之前遇到过“不支持对 SQL 的转换”的问题,其中某些类型是最近的 DateTime 类型。但是我上面的测试和this link证明SQL翻译应该支持AddHours方法。

如果有人能告诉我我在这里做错了什么(或解决此问题的不同解决方法),我将不胜感激。

【问题讨论】:

    标签: sql linq-to-sql datetime extension-methods utc


    【解决方案1】:

    您必须从表达式树的角度来考虑它,这就是 Linq-to-SQL 解析查询以将其转换为 SQL 的方式。

    当检查树时,它会看到一个DateTime 对象,然后检查它调用的方法是否是支持的方法之一(AddAddHours 等)所以当你直接使用该方法时工作正常。

    当您使用其他一些扩展方法时,它无法进入该方法的内部以查看其作用,因为有关该方法主体的信息不在表达式树中,而是隐藏在 IL 中。所以扩展方法的内容是否支持无关紧要,因为Linq-to-SQL无法计算出内容是什么。

    创建方法的重点是封装和信息隐藏,这通常在应用程序开发中效果很好,但不幸的是,这里它隐藏了 Linq-to-SQL 的信息,您需要能够看到这些信息。


    针对已编辑的问题 - 您如何解决这个问题?如果你想在 Linq 表达式中保留日期计算,你唯一能做的就是不使用扩展方法,而是直接在 DateTime 对象上使用 AddHours(3)

    这是 Linq 的不幸限制之一。像许多事情一样,它是一个有点泄漏的抽象,虽然在一系列源上提供通用语法,但对源的提供者可以/将支持哪些操作有不同的限制和限制(例如,这在 Linq-to 中可以很好地工作-Objects,因为它不需要翻译表达式树来执行它)。

    【讨论】:

    • 这是一个很棒的解释。但我不知道它对我有什么帮助。对我的问题有什么具体建议吗?
    • 我打算使用 Linq 表达式来做这件事 - albahari.com/nutshell/predicatebuilder.aspx 谢谢你的帮助
    【解决方案2】:

    似乎 LINQ-to-SQL 能够确定 RiyadhTimeFromUtc 实际上只是对 AddHours(3) 的调用,它必须对您的代码进行一些非常复杂的分析。假设你写了:

    public static DateTime RiyadhTimeFromUtc(this DateTime utcTime)
    {
        if (Random.GetInt() < 99) {
           return utcTime.AddHours(3);
        } else {
           return utcTime.AddDays(5);
        }
    }
    

    它将如何将其转换为 SQL?请参阅this discussion 了解更多信息。

    【讨论】:

    • 感谢底部的链接。这让我走上了正轨
    猜你喜欢
    • 2016-05-20
    • 1970-01-01
    • 2017-10-21
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-29
    • 1970-01-01
    相关资源
    最近更新 更多