要了解这个问题,您必须了解 IEnumerable 和 IQueryable 之间的区别。
IEnumerable
实现IEnumerable<...> 的类的对象表示类似对象的序列。它包含获取序列的第一个元素的所有内容,只要你有一个元素,你就可以尝试获取下一个元素。
在最低级别,这是使用GetEnumerator 并反复调用MoveNext() / Current 完成的,如下所示:
IEnumerable<Movie> movies = ...
IEnumerator<Movie> enumerator = movies.GetEnumerator();
// try to get the next element:
while (enumerator.MoveNext())
{
// There is a next element
Movie movie = enumerator.Current;
ProcessMovie(movie);
}
内心深处foreach 会做这样的事情。每个不返回 IEnumerable<...> 的 LINQ 方法也会在内部调用 GetEnumerator / MoveNext / Current。
IEnumerable 旨在由您的进程执行,因此 IEnumerable 可以访问您的所有过程。
可查询
虽然 IQueryable 看起来像 IEnumerable,但它代表了获得可枚举序列的潜力。
为此,IQueryable 有一个 Expression 和一个 Provider。表达式包含必须以某种通用格式获取的数据; Provider 知道他必须从哪里获取数据(通常是数据库管理系统),以及获取数据时使用什么语言(通常是 SQL)。
只要您连接返回 IQueryable<...> 的 LINQ 方法,表达式就会发生变化。查询未执行,数据库未联系。我们说 LINQ 方法使用延迟执行或延迟执行。连接这样的 LINQ 语句并不昂贵。
不返回 IQueryable<...> 的 LINQ 方法,如 ToList()、ToDictionary()、FirstOrDefault()、Count()、Any(),是昂贵的,就像 foreach 一样,它们会在内部调用 GetEnumerator ()。
当您调用GetEnumerator() 时,Expression 会发送给 Provider,Provider 会将 Expression 转换为 SQL 并执行查询。获取的数据以IEnumerator<...> 的形式返回,您可以调用其中的MoveNext() / Current。
有些提供商比其他提供商更聪明。例如,其中一些在您获取 Enumerator 时不会获取数据,而是在第一个 MoveNext 时获取数据。其他人不会一次获取所有请求的数据,而是“每页”获取数据,因此如果您决定仅枚举两个或三个项目,则仅获取电影的第一页,而不是全部 10000 个。
但这与我的问题有什么关系?
您使用了您的 Provider 不知道的方法:Convert.ToDateTime。因此它无法将其转换为 SQL。事实上,有几种 LINQ 方法是实体框架不支持的。见Supported and Unsupported LINQ methods
您的编译器不知道 Provider 有多聪明,因此您的编译器不会抱怨。您将在运行时收到错误。
所以你不能使用Convert.ToDateTime,也不能使用Datetime.Parse之类的方法。
怎么办?
您写道要转换的字符串格式为“YYYY-MM-DD”。
您可以做的是使用字符串处理例程将它们分成“YYYY”、“MM”和“DD”。是否可以使用String.SubString 取决于您的提供商。
然后使用类DbFunctions 到CreateDateTime
.Where(x => ... && DbFunctions.CreateDateTime(
x.TransDate.SubString(0,4), // YYYY
x.TransDate.SubString(5, 2), // MM
x.TransDate.SubString(8, 2), // DD
0, 0, 0) < endDate;
如果您的 Provider 也不接受 SubString,请搜索其他方法来提取 YYYY、MM 和 DD。我知道Sqlite has a Date 将字符串转换为日期时间的方法。
如果您找不到任何合适的字符串操作例程,请考虑将 endDate 转换为格式“YYYY-MM-DD”并返回比较 TransDate 字符串与 endDateSTring
string endDateString = String.Format("{0:D04}-{1:D02}-{2:D02}", endDate.Year, endDate.Month, ...)
稍微摆弄一下,直到你得到正确的格式。然后使用:
.Where(x => ... && x.TransDate < endDateString)
如果这也不起作用,请自行创建 SQL 查询。