如何只比较日期部分和linq表达式?

时间:2014-03-10 09:14:19

标签: linq linq-expressions

我只想为网格视图制作列过滤器。简单我只想用一些额外的东西过滤网格视图列。在这里,我创建了一个返回可查询结果的IQueryable。

这是我的代码:

------------------------------------------ Updated- -----------------------------------------------

public static IQueryable<T> FilterForColumn<T>(this IQueryable<T> queryable, string colName, string searchText)
{
    if (colName != null && searchText != null)
    {
        var parameter = Expression.Parameter(typeof(T), "m");
        var propertyExpression = Expression.Property(parameter, colName);
        System.Linq.Expressions.ConstantExpression searchExpression = null;
        System.Reflection.MethodInfo containsMethod = null;
        System.Linq.Expressions.MethodCallExpression body = null;
        System.Nullable<DateTime> nextDate = null;
        Expression ex1 = null;
        Expression ex2 = null;
        switch (colName)
        {
            case "JobID":
            case "FileSize":
            case "TotalFileSize":
                Int64? size = Convert.ToInt64(searchText);
                searchExpression = Expression.Constant(searchText);
                containsMethod = typeof(Int64?).GetMethod("Equals", new[] { typeof(Int64?) });
                body = Expression.Call(propertyExpression, containsMethod, searchExpression);
                break;
            case "PublishDate":
            case "Birth_date":
            case "Anniversary_date":
            case "Profile_Updated_datetime":
            case "CompletedOn":
                DateTime? currentDate = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
                nextDate = currentDate.Value.AddDays(1);
                ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate));
                ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate));
                body = Expression.AndAlso(ex1, ex2);
                break;
            case "Created_datetime":
            case "Reminder_Date":
            case "News_date":
            case "thought_date":
            case "SubscriptionDateTime":
            case "Register_datetime":
            case "CreatedOn":
                DateTime dt1 = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
                nextDate = currentDate.Value.AddDays(1);
                ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate));
                ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate));
                body = Expression.AndAlso(ex1, ex2);
                break;
            default :
                searchExpression = Expression.Constant(searchText);
                containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                body = Expression.Call(propertyExpression, containsMethod, searchExpression);
                break;
        }
        var predicate = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });
        return queryable.Where(predicate);
    }
    else
    {
        return queryable;
    }
}

这里这个解决方案给出了一些编译时错误:

Error   9   Cannot implicitly convert type 'System.Linq.Expressions.BinaryExpression' to 'System.Linq.Expressions.MethodCallExpression' F:\EasyWeb\App_Code\Helper.cs   47  28  F:\EasyWeb\

在DateTime的情况下,我只想过滤DateTime列,只有Date而不是整个DATETIME值。

这里我只是提出了所需的东西:

SELECT [t8].[Id], [t8].[Title], [t8].[value] AS [Publisher], [t8].[value2] AS [ToUser], [t8].[Sent_Datetime] AS [PublishDate], [t8].[IsFileAttached] AS [IsFile], [t8].[Category_name] AS [CategoryName], [t8].[value3] AS [status_name], [t8].[value4] AS [Group_name], [t8].[TotalFileSize] AS [FileSize]
FROM (
    SELECT [t0].[Id], [t0].[Title], (
        SELECT TOP (1) [t3].[value]
        FROM (
            SELECT ([t2].[First_name] + ' ') + [t2].[Last_name] AS [value], [t2].[Id]
            FROM [dbo].[tbl_User_master] AS [t2]
            ) AS [t3]
        WHERE [t3].[Id] = [t0].[User_id]
        ) AS [value], (
        SELECT TOP (1) [t5].[value]
        FROM (
            SELECT ([t4].[First_name] + ' ') + [t4].[Last_name] AS [value], [t4].[Id]
            FROM [dbo].[tbl_User_master] AS [t4]
            ) AS [t5]
        WHERE ([t5].[Id]) = [t0].[ToUser_id]
        ) AS [value2], [t0].[Sent_Datetime], [t0].[IsFileAttached], [t1].[Category_name], (
        SELECT TOP (1) [t6].[status_name]
        FROM [dbo].[tbl_status_master] AS [t6]
        WHERE ([t6].[Id]) = [t0].[status_id]
        ) AS [value3], (
        SELECT TOP (1) [t7].[Group_name]
        FROM [dbo].[tbl_Group_master] AS [t7]
        WHERE ([t7].[Id]) = [t0].[group_id]
        ) AS [value4], [t0].[TotalFileSize], [t0].[ToUser_id], [t0].[User_id]
    FROM [dbo].[tbl_Post_History] AS [t0]
    INNER JOIN [dbo].[tbl_Category_master] AS [t1] ON [t0].[Category_id] = [t1].[Id]
    ) AS [t8]
WHERE (CAST(CONVERT(CHAR(10), [t8].[Sent_Datetime], 102) AS DATETIME) = '12/24/2013' ) AND (([t8].[ToUser_id] = 3) OR ([t8].[ToUser_id] IS NULL)) AND ([t8].[User_id] <> 3)
ORDER BY [t8].[Sent_Datetime] DESC

这里显示了我们将使用可查询的所需输出或逻辑。

但是,这个方法Equals检查整个日期时间时会出现一个缺点。 这种方法是否可以强制仅从列中检查日期部分?

------------------------------------ 2-更新----- ------------------------------------

为了解决这个问题,我使用了这种技术:

 public static IQueryable<T> FilterForColumn<T>(this IQueryable<T> queryable, string colName, string searchText)
    {
        if (colName != null && searchText != null)
        {
            var parameter = Expression.Parameter(typeof(T), "m");
            var propertyExpression = Expression.Property(parameter, colName);
            System.Linq.Expressions.ConstantExpression searchExpression = null;
            System.Reflection.MethodInfo containsMethod = null;
            System.Linq.Expressions.BinaryExpression body = null;
            DateTime? currentDate = null;
            DateTime? nextDate = null;
            Expression ex1 = null;
            Expression ex2 = null;
            switch (colName)
            {
                case "JobID":
                case "FileSize":
                case "TotalFileSize":
                    Int64? size = Convert.ToInt64(searchText);
                    searchExpression = Expression.Constant(searchText);
                    containsMethod = typeof(Int64?).GetMethod("Equals", new[] { typeof(Int64?) });
                    //body = Expression.Call(propertyExpression, containsMethod, searchExpression);
                    break;
                case "PublishDate":
                case "Birth_date":
                case "Anniversary_date":
                case "Profile_Updated_datetime":
                case "CompletedOn":
                    currentDate = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
                    nextDate = currentDate.Value.AddDays(1);
                    ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate));
                    ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate));
                    body = Expression.AndAlso(ex1, ex2);
                    break;
                case "Created_datetime":
                case "Reminder_Date":
                case "News_date":
                case "thought_date":
                case "SubscriptionDateTime":
                case "Register_datetime":
                case "CreatedOn":
                    currentDate = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
                    nextDate = currentDate.Value.AddDays(1);
                    ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate));
                    ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate));
                    body = Expression.AndAlso(ex1, ex2);
                    break;
                default :
                    searchExpression = Expression.Constant(searchText);
                    containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                    //body = Expression.Call(propertyExpression, containsMethod, searchExpression);
                    break;
            }
            var predicate = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });
            return queryable.Where(predicate);
        }
        else
        {
            return queryable;
        }
    }

它给我运行时错误,如:

Server Error in '/EasyWeb' Application.

The binary operator GreaterThanOrEqual is not defined for the types 'System.Nullable`1[System.DateTime]' and 'System.DateTime'.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.InvalidOperationException: The binary operator GreaterThanOrEqual is not defined for the types 'System.Nullable`1[System.DateTime]' and 'System.DateTime'.

Source Error: 


Line 44:                     currentDate = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
Line 45:                     nextDate = currentDate.Value.AddDays(1);
Line 46:                     ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate));
Line 47:                     ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate));
Line 48:                     body = Expression.AndAlso(ex1, ex2);

Source File: f:\EasyWeb\App_Code\Helper.cs    Line: 46 

Stack Trace: 


[InvalidOperationException: The binary operator GreaterThanOrEqual is not defined for the types 'System.Nullable`1[System.DateTime]' and 'System.DateTime'.]
   System.Linq.Expressions.Expression.GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, String name, Expression left, Expression right, Boolean liftToNull) +752213
   System.Linq.Expressions.Expression.GetComparisonOperator(ExpressionType binaryType, String opName, Expression left, Expression right, Boolean liftToNull) +221
   System.Linq.Expressions.Expression.GreaterThanOrEqual(Expression left, Expression right, Boolean liftToNull, MethodInfo method) +53
   System.Linq.Expressions.Expression.GreaterThanOrEqual(Expression left, Expression right) +8
   Helper.FilterForColumn(IQueryable`1 queryable, String colName, String searchText) in f:\EasyWeb\App_Code\Helper.cs:46
   Admin_Post_History.FillGrid(String CommandName, String ColumnName, String SearchText) in f:\EasyWeb\Admin\Post_History.aspx.cs:79
   Admin_Post_History.btnsearch_Click(Object sender, EventArgs e) in f:\EasyWeb\Admin\Post_History.aspx.cs:2375
   System.Web.UI.WebControls.Button.OnClick(EventArgs e) +111
   System.Web.UI.WebControls.Button.RaisePostBackEvent(String eventArgument) +110
   System.Web.UI.WebControls.Button.System.Web.UI.IPostBackEventHandler.RaisePostBackEvent(String eventArgument) +10
   System.Web.UI.Page.RaisePostBackEvent(IPostBackEventHandler sourceControl, String eventArgument) +13
   System.Web.UI.Page.RaisePostBackEvent(NameValueCollection postData) +36
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +1565

Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053

-------------------------------- 3更新---------- ---------------------------------

这是我要查询的内容:

case "Inbox":
                        lbl_disply.Text = "Inbox";
                        lbut_showinbox.Font.Bold = true;
                        lbut_showoutbox.Font.Bold = false;
                        lbut_showdraffs.Font.Bold = false;
                        lbut_showtrash.Font.Bold = false;
                        var query1 = db.Posts.Where(p => (p.ToUser_id.Equals(user_id) || p.ToUser_id.Equals(null)) && p.User_id != user_id).OrderByDescending(p=>p.Sent_Datetime).Select(p => new
                        {
                            Id = p.Id,
                            Title = p.Title,
                            Publisher = db.Users.Where(u => u.Id.Equals(p.User_id)).Select(u => u.First_name + ' ' + u.Last_name).FirstOrDefault(),
                            ToUser = db.Users.Where(u => u.Id.Equals(p.ToUser_id)).Select(u => u.First_name + ' ' + u.Last_name).FirstOrDefault(),
                            PublishDate = p.Sent_Datetime,
                            IsFile = p.IsFileAttached,
                            CategoryName = db.Categories.Where(c => c.Id.Equals(p.Category_id)).Select(c => c.Category_name).FirstOrDefault(),
                            status_name = db.Status.Where(s => s.Id.Equals(p.status_id)).Select(s => s.status_name).FirstOrDefault(),
                            Group_name = db.Groups.Where(g => g.Id.Equals(p.group_id)).Select(g => g.Group_name).FirstOrDefault(),
                            FileSize = p.TotalFileSize
                        }).FilterForColumn(ColumnName, SearchText).ToList();

在网格视图填充

DataSet myDataSet = new DataSet();
                        DataTable dt = new DataTable();
                        dt.Columns.Add(new DataColumn("Id", typeof(int)));
                        dt.Columns.Add(new DataColumn("IsRead", typeof(bool)));
                        dt.Columns.Add(new DataColumn("IsImp", typeof(bool)));
                        dt.Columns.Add(new DataColumn("Title", typeof(string)));
                        dt.Columns.Add(new DataColumn("Publisher", typeof(string)));
                        dt.Columns.Add(new DataColumn("ToUser", typeof(string)));
                        dt.Columns.Add(new DataColumn("PublishDate", typeof(DateTime?)));
                        dt.Columns.Add(new DataColumn("IsFile", typeof(bool)));
                        dt.Columns.Add(new DataColumn("CategoryName", typeof(string)));
                        dt.Columns.Add(new DataColumn("status_name", typeof(string)));
                        dt.Columns.Add(new DataColumn("Group_name", typeof(string)));
                        dt.Columns.Add(new DataColumn("FileSize", typeof(string)));
                        foreach (var item in query1)

我将这个PublishDate声明为typeof(DateTime?)但是这给了我运行时错误,如:

Server Error in '/EasyWeb' Application.

DataSet does not support System.Nullable<>.

Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code. 

Exception Details: System.NotSupportedException: DataSet does not support System.Nullable<>.

Source Error: 


Line 101:                        dt.Columns.Add(new DataColumn("Publisher", typeof(string)));
Line 102:                        dt.Columns.Add(new DataColumn("ToUser", typeof(string)));
Line 103:                        dt.Columns.Add(new DataColumn("PublishDate", typeof(DateTime?)));
Line 104:                        dt.Columns.Add(new DataColumn("IsFile", typeof(bool)));
Line 105:                        dt.Columns.Add(new DataColumn("CategoryName", typeof(string)));

Source File: f:\EasyWeb\Admin\Post_History.aspx.cs    Line: 103 

Stack Trace: 


[NotSupportedException: DataSet does not support System.Nullable<>.]
   System.Data.DataColumn..ctor(String columnName, Type dataType, String expr, MappingType type) +4826536
   System.Data.DataColumn..ctor(String columnName, Type dataType) +12
   Admin_Post_History.FillGrid(String CommandName, String ColumnName, String SearchText) in f:\EasyWeb\Admin\Post_History.aspx.cs:103
   Admin_Post_History.Page_Load(Object sender, EventArgs e) in f:\EasyWeb\Admin\Post_History.aspx.cs:59
   System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp, Object o, Object t, EventArgs e) +14
   System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object sender, EventArgs e) +35
   System.Web.UI.Control.OnLoad(EventArgs e) +99
   System.Web.UI.Control.LoadRecursive() +50
   System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +627

Version Information: Microsoft .NET Framework Version:2.0.50727.3053; ASP.NET Version:2.0.50727.3053

--------------------------------- 4更新--------- -------------------------------

我检查我的dbml文件,这是屏幕截图,以验证它是否可以为空

enter image description here

2 个答案:

答案 0 :(得分:4)

要实现您的目标,您可以使用谓词

WHERE Sent_Datetime >= '20131224' AND Sent_Datetime < '20131225'

所以你可以使用这个表达式

DateTime currentDate = DateTime.ParseExact("06/01/2008", "dd/MM/yyyy", null);
DateTime nextDate = currentDate.AddDays(1);

Expression ex1 = Expression.GreaterThanOrEqual(
                       propertyExpression, Expression.Constant(currentDate));
Expression ex2 = Expression.LessThan(
                       propertyExpression, Expression.Constant(nextDate));
Expression body = Expression.AndAlso(ex1, ex2);

var predicate = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });

当然,在这里你有一个sargable谓词。

<强>更新

我为您创建了完整的示例:

public static IQueryable<T> FilterForColumn<T>(this IQueryable<T> queryable, string colName, string searchText)
{
   if (colName != null && searchText != null)
   {
       var parameter = Expression.Parameter(typeof(T), "m");
       var propertyExpression = Expression.Property(parameter, colName);
       System.Linq.Expressions.ConstantExpression searchExpression = null;
       System.Reflection.MethodInfo containsMethod = null;
       // this must be of type Expression to accept different type of expressions
       // i.e. BinaryExpression, MethodCallExpression, ...
       System.Linq.Expressions.Expression body = null;
       Expression ex1 = null;
       Expression ex2 = null;
       switch (colName)
       {
           case "JobID":
           case "FileSize":
           case "TotalFileSize":
               Int64? size = Convert.ToInt64(searchText);
               searchExpression = Expression.Constant(searchText);
               containsMethod = typeof(Int64?).GetMethod("Equals", new[] { typeof(Int64?) });
               body = Expression.Call(propertyExpression, containsMethod, searchExpression);
               break;
           // section for DateTime? properties
           case "PublishDate":
           case "Birth_date":
           case "Anniversary_date":
           case "Profile_Updated_datetime":
           case "CompletedOn":
               DateTime currentDate = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
               DateTime nextDate = currentDate.AddDays(1);
               ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate, typeof(DateTime?)));
               ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate, typeof(DateTime?)));
               body = Expression.AndAlso(ex1, ex2);
               break;
           // section for DateTime properties
           case "Created_datetime":
           case "Reminder_Date":
           case "News_date":
           case "thought_date":
           case "SubscriptionDateTime":
           case "Register_datetime":
           case "CreatedOn":
               DateTime currentDate = DateTime.ParseExact(searchText, "dd/MM/yyyy", null);
               DateTime nextDate = currentDate.AddDays(1);
               ex1 = Expression.GreaterThanOrEqual(propertyExpression, Expression.Constant(currentDate));
               ex2 = Expression.LessThan(propertyExpression, Expression.Constant(nextDate));
               body = Expression.AndAlso(ex1, ex2);
               break;
           default :
               searchExpression = Expression.Constant(searchText);
               containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
               body = Expression.Call(propertyExpression, containsMethod, searchExpression);
               break;
       }
       var predicate = Expression.Lambda<Func<T, bool>>(body, new[] { parameter });
       return queryable.Where(predicate);
   }
   else
   {
       return queryable;
   }
}

答案 1 :(得分:2)

您可以使用SqlFunctions.DateDiff函数指定"day"值作为datepart参数。

var result = entities
    .Where(item =>
        SqlFunctions.DateDiff("day", item.DateProperty, dateToCompare) == 0);