Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to compare only date part with linq expression?

I just want to make Column Filter for grid view. Simple I just want to filter grid view column with some extra stuff. Here I have created one IQueryable that returns queryable result.

Here is my code :

------------------------------------------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;
    }
}

here this solution gives some compile time error :

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\

Here at case of DateTime I just want to filter DateTime column with only Date not whole DATETIME value.

Here I just put required things :

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

Here this shows required output or logic that we will do with queryable.

But, here one drawback occurs while this method Equals check whole Date Time. Is that possible with this method to force only check Date Part from column?

------------------------------------2-Updated-----------------------------------------

for overwhelming this problem i use this technique :

 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;
        }
    }

it's give me run time error like :

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 Update-------------------------------------------

here is what i'm querying :

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();

at grid view filling

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)

i declared this PublishDate as typeof(DateTime?) but this gives me run time error like :

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 Update----------------------------------------

i check my dbml file and this is screen shot for verify that it's nullable

enter image description here

like image 843
shalin gajjar Avatar asked Mar 10 '14 09:03

shalin gajjar


People also ask

How to Compare date in LINQ query?

Condition 1) StartDate is less than or equal to current date and enddate is Greater than current date. Condition 2) End date is less than today/current date. and if we have to get only count of rows not the dt row.

How do I check if one date is greater than another in C#?

Compare() Method in C# This method is used to compare two instances of DateTime and returns an integer that indicates whether the first instance is earlier than, the same as, or later than the second instance.


1 Answers

To achieve what you want you can use predicate

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

so you can use this expression

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 });

Of course, here you have sargable predicate.

Update

I've created the complete example for you:

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;
   }
}
like image 73
Hamlet Hakobyan Avatar answered Sep 19 '22 16:09

Hamlet Hakobyan