在IQueryable结果中过滤DateTime

时间:2018-08-16 19:19:14

标签: asp.net-mvc-4 asp.net-mvc-5 asp.net-core-mvc

我有一个在页面上显示用户列表的应用程序。客户端可以选择过滤用户。在我的存储库中,我有一个Linq查询,该查询返回User的IQueryable。我将筛选器和分页应用于IQueryable结果,并调用.ToList()。我无法使日期过滤正常工作。如果我在日期搜索中包含“ /”,它将不会返回任何内容。例如,我有一个DOB 07/10/2000的患者。当我键入“ 07”时,它将返回患者,但如果键入“ 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是下面显示的Parameters类的实例。它包含在搜索框中输入的值。

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.

2 个答案:

答案 0 :(得分:0)

之所以会出现此异常,是因为EF Core不能将所有c#函数都转换为数据库级函数。

在EFCore中的db列上不允许使用c#的ToLower()。

“用户是用户的IQueryable。如果我在用户上调用.ToList()并在之后应用过滤器,则它可以正常工作。仅当将其应用于IQueryable用户时,它才不起作用”->由于IQueryable。在使用IQueryable的情况下,将过滤器应用于数据库本身,然后再将记录提取到内存中。在IQueryable上调用ToList(),获取内存中的记录,并成为IEnumerable。

如果您将Microsoft SQL Server用于数据库用途,则可以签出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解析为Datetime并使用上述给定URL中的任何EF.DateDiff()函数。

您还可以定义自己的自定义DbFunction,请参考此post

答案 1 :(得分:-1)

如下更改代码:

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对象的值转换为其等效的短日期字符串表示形式。

更新s.DateOfBirth.ToString("MM/dd/yyyy")支持EntityFrameworkCore,似乎您正在使用EntityFramework之后仅支持s.DateOfBirth.ToString()的{​​{1}}。在EF 6.1之前,它甚至不支持EF 6.1

要解决此问题,请尝试将s.DateOfBirth.ToString更改为IQueryable

AsEnumerable