在 IQueryable 结果中过滤 DateTime
Filtering DateTime in IQueryable Result
我有一个在页面上显示用户列表的应用程序。客户端可以选择过滤用户。在我的存储库中,我有一个 Linq 查询 returns 一个 IQueryable of User。我正在对 IQueryable 结果应用过滤器和分页并调用 .ToList()。我无法使日期过滤正常工作。如果我在日期搜索中包含“/”,它不会 return 任何东西。例如,我有一位 DOB 07/10/2000 的患者。当我输入“07”时,它 return 是病人,但如果我输入“07/”,它就没有。如果不在分页前调用 .ToList(),我可以对以下查询进行哪些更改,以使日期过滤正常工作?
IQueryable<User> users = _db.Users.Where(x => x.UserID == userID && x.Active == true);
if (!string.IsNullOrWhiteSpace(param.filterValue))
{
users = users.Where(x => x.firstName.ToLower().Contains(param.filterValue.ToLower())
|| x.lastName.ToLower().Contains(param.filterValue.ToLower())
|| x.dateOfBirth.ToString().Contains(param.filterValue.ToLower())
);
}
2018 年 8 月 17 日更新
dateOfBirth 是一个 DateTime 字段。但是,时间被忽略了。 param.filterValue 是参数 class 的实例,如下所示。它包含在搜索框中输入的值。
public class Parameters
{
public int MAX_PAGE_SIZE {
get {
return 100;
}
}
public string filterValue { get; set; }
public int PageIndex { get; set; }
public int PageSize { get; set; }
}
此外,我尝试使用此更改。
x.dateOfBirth.ToString("MM/dd/yyyy").Contains(param.filterValue.ToLower())
抛出异常
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
更改您的代码如下:
if (!String.IsNullOrWhiteSpace(SearchString))
{
users = users.Where(s => s.LastName.ToLower().Contains(SearchString.ToLower())
|| s.FirstName.ToLower().Contains(SearchString.ToLower())
|| s.DateOfBirth.ToString("MM/dd/yyyy").Contains(SearchString.ToLower()));
}
将当前 DateTime 对象的值转换为其等效的短日期字符串表示形式。
更新:
EntityFrameworkCore
支持 s.DateOfBirth.ToString("MM/dd/yyyy")
,看来你用的 EntityFramework
只支持 EF 6.1
之后的 s.DateOfBirth.ToString()
。在EF 6.1
之前,它甚至不支持s.DateOfBirth.ToString
。
要解决此问题,请尝试将 IQueryable
更改为 AsEnumerable
。
var users = db.Product.AsEnumerable();
if (!string.IsNullOrWhiteSpace(filterValue))
{
users = users.Where(x =>
x.CreationTime.ToString("MM/dd/yyyy")
.Contains(filterValue.ToLower()));
}
var result = users.ToList();
您收到此异常是因为并非所有 c# 函数都可以通过 EF Core 转换为数据库级函数。
EFCore 中的数据库列不允许使用 c# 的 ToLower()。
“用户是用户的 IQueryable。如果我在用户上调用 .ToList() 并在之后应用过滤器,它工作正常。只有当我将它应用到 IQueryable 用户时它才不起作用” -> 它正在发生,因为 IQueryable。在 IQueryable 的情况下,在将记录提取到内存中之前,过滤器将应用于数据库本身。在 IQueryable 上调用 ToList(),获取内存中的记录,它变成一个 IEnumerable。
如果您将 Microsoft SQL 服务器用于您的数据库目的,那么您可以查看 Microsoft 定义的以下 DbFunctions。
对于名字和姓氏过滤器,您可以这样写
users.Where(x => EF.Functions.Contains(x.firstName, param.filterValue.ToLower())
|| EF.Functions.Contains(x.lastName), param.filterValue.ToLower())
);
关于 x.dateOfBirth,不确定为什么要将 Datetime 字段转换为字符串,然后调用 Contains 函数。如果你的数据库中已经是 NVarchar 或 Varchar 数据类型,那么你可以像 firstName/lastName
EF.Functions.Contains(x.dateOfBirth, param.filterValue.ToLower())
或者如果它是日期时间,那么您可以将 param.filterValue 解析为日期时间并使用上面给定的 url.
中的任何 EF.DateDiff() 函数
你也可以定义自己的自定义DbFunctions,参考这个post
我有一个在页面上显示用户列表的应用程序。客户端可以选择过滤用户。在我的存储库中,我有一个 Linq 查询 returns 一个 IQueryable of User。我正在对 IQueryable 结果应用过滤器和分页并调用 .ToList()。我无法使日期过滤正常工作。如果我在日期搜索中包含“/”,它不会 return 任何东西。例如,我有一位 DOB 07/10/2000 的患者。当我输入“07”时,它 return 是病人,但如果我输入“07/”,它就没有。如果不在分页前调用 .ToList(),我可以对以下查询进行哪些更改,以使日期过滤正常工作?
IQueryable<User> users = _db.Users.Where(x => x.UserID == userID && x.Active == true);
if (!string.IsNullOrWhiteSpace(param.filterValue))
{
users = users.Where(x => x.firstName.ToLower().Contains(param.filterValue.ToLower())
|| x.lastName.ToLower().Contains(param.filterValue.ToLower())
|| x.dateOfBirth.ToString().Contains(param.filterValue.ToLower())
);
}
2018 年 8 月 17 日更新
dateOfBirth 是一个 DateTime 字段。但是,时间被忽略了。 param.filterValue 是参数 class 的实例,如下所示。它包含在搜索框中输入的值。
public class Parameters
{
public int MAX_PAGE_SIZE {
get {
return 100;
}
}
public string filterValue { get; set; }
public int PageIndex { get; set; }
public int PageSize { get; set; }
}
此外,我尝试使用此更改。
x.dateOfBirth.ToString("MM/dd/yyyy").Contains(param.filterValue.ToLower())
抛出异常
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.
更改您的代码如下:
if (!String.IsNullOrWhiteSpace(SearchString))
{
users = users.Where(s => s.LastName.ToLower().Contains(SearchString.ToLower())
|| s.FirstName.ToLower().Contains(SearchString.ToLower())
|| s.DateOfBirth.ToString("MM/dd/yyyy").Contains(SearchString.ToLower()));
}
将当前 DateTime 对象的值转换为其等效的短日期字符串表示形式。
更新:
EntityFrameworkCore
支持 s.DateOfBirth.ToString("MM/dd/yyyy")
,看来你用的 EntityFramework
只支持 EF 6.1
之后的 s.DateOfBirth.ToString()
。在EF 6.1
之前,它甚至不支持s.DateOfBirth.ToString
。
要解决此问题,请尝试将 IQueryable
更改为 AsEnumerable
。
var users = db.Product.AsEnumerable();
if (!string.IsNullOrWhiteSpace(filterValue))
{
users = users.Where(x =>
x.CreationTime.ToString("MM/dd/yyyy")
.Contains(filterValue.ToLower()));
}
var result = users.ToList();
您收到此异常是因为并非所有 c# 函数都可以通过 EF Core 转换为数据库级函数。
EFCore 中的数据库列不允许使用 c# 的 ToLower()。
“用户是用户的 IQueryable。如果我在用户上调用 .ToList() 并在之后应用过滤器,它工作正常。只有当我将它应用到 IQueryable 用户时它才不起作用” -> 它正在发生,因为 IQueryable。在 IQueryable 的情况下,在将记录提取到内存中之前,过滤器将应用于数据库本身。在 IQueryable 上调用 ToList(),获取内存中的记录,它变成一个 IEnumerable。
如果您将 Microsoft SQL 服务器用于您的数据库目的,那么您可以查看 Microsoft 定义的以下 DbFunctions。
对于名字和姓氏过滤器,您可以这样写
users.Where(x => EF.Functions.Contains(x.firstName, param.filterValue.ToLower())
|| EF.Functions.Contains(x.lastName), param.filterValue.ToLower())
);
关于 x.dateOfBirth,不确定为什么要将 Datetime 字段转换为字符串,然后调用 Contains 函数。如果你的数据库中已经是 NVarchar 或 Varchar 数据类型,那么你可以像 firstName/lastName
EF.Functions.Contains(x.dateOfBirth, param.filterValue.ToLower())
或者如果它是日期时间,那么您可以将 param.filterValue 解析为日期时间并使用上面给定的 url.
中的任何 EF.DateDiff() 函数你也可以定义自己的自定义DbFunctions,参考这个post