考虑我的 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:方法'System.DateTime RiyadhTimeFromUtc(System.DateTime)'没有支持的SQL转换。

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

我遇到了“没有支持的SQL翻译”。某些类型和最近的DateTime之前的问题。但我上面的测试和此链接证明了AddHours方法应该是在SQL翻译中受支持。

如果有人能告诉我这里我做错了什么(或者解决这个问题的方法不同),我真的很感激。

有帮助吗?

解决方案

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

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

当你使用其他一些扩展方法时,它不能去查看该方法以查看它的作用,因为有关该方法的主体的信息不在表达式树中,它隐藏在IL中。因此,是否支持扩展方法的内容并不重要,因为Linq-to-SQL无法确定内容是什么。

创建方法的关键是封装和信息隐藏,这通常适用于应用程序开发,但不幸的是,它隐藏了Linq-to-SQL中需要能够查看信息的信息。


回应编辑过的问题 - 你如何解决这个问题?如果你想在Linq表达式中保留日期计算,你唯一能做的就是不要使用扩展方法,只需直接在 AddHours(3)上使用< code> DateTime 对象。

这是Linq的一个不幸的局限。像许多事情一样,它是一个有点漏洞的抽象,虽然在一系列源代码上提供了通用语法,但对源代码可以/将支持的操作有不同的限制和限制(例如,这在Linq-to中完全可以正常工作) - 对象,因为它不需要翻译表达式树来执行它。)

其他提示

似乎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?请参阅此讨论获取更多信息。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top