在 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