Home > database >  Handling DateTimes with Linq Expression
Handling DateTimes with Linq Expression

Time:08-08

I'm trying to create a Linq Expression to compare a date column with DateTime.Now

Here's my code

private void ProcessQueueEntries()
{
    _logger.LogInformation("ProcessQueueEntries");

    try
    {
        var entries = _repo.ReadQueueEntries()
                           .Where(MatchQueueEntries())
                           .OrderBy(t => t.TaskNumber)
                           .ToList()
                           .Select(te => te.ToQueueEntry());
        ....
    }
    catch (Exception ex)
    {
        _logger.LogError(ex, "ProcessQueueEntries");
    }
}

private static Expression<Func<TaskEntry, bool>> MatchQueueEntries()
{            
    var nowValue = Expression.Constant(DateTime.Now, typeof(DateTime?));
    var taskEntryExpr = Expression.Parameter(typeof(TaskEntry));
    var scheduledTimeValue = Expression.PropertyOrField(taskEntryExpr, "ScheduledTime");            
    var scheduledTestExpr = Expression.LessThan(scheduledTimeValue, nowValue);

    return Expression.Lambda<Func<TaskEntry, bool>>(scheduledTestExpr, taskEntryExpr);
}

It is generating the following sql

SELECT [i].[TaskNumber], ...
FROM [Tasks] AS [i]
WHERE ... 
AND ([i].[ScheduledTime] < '2022-08-08T13:36:31.4981662 01:00')
ORDER BY [i].[TaskNumber]

and generating an conversion exception

Microsoft.Data.SqlClient.SqlException: 
'Conversion failed when converting date and/or time from character string.'

What is the correct way to express DateTime.Now within a Linq expression such that it doesn't generate an exception like this - or perhaps there's a setting on the datacontext which I've not set correctly to handle dates?

CodePudding user response:

DateTime.Now is static property call and you have to repeat that in Expresion Tree:

private static PropertyInfo _nowProperty = typeof(DateTime).GetProperty(nameof(DateTime.Now), BindingFlags.Static | BindingFlags.Public);

private static Expression<Func<TaskEntry, bool>> MatchQueueEntries()
{
    var nowValue           = (Expression)Expression.Property(null, _nowProperty);
    var taskEntryExpr      = Expression.Parameter(typeof(TaskEntry));
    var scheduledTimeValue = Expression.PropertyOrField(taskEntryExpr, "ScheduledTime");

    if (scheduledTimeValue.Type != nowValue.Type)
        nowValue = Expression.Convert(nowValue, scheduledTimeValue.Type);

    var scheduledTestExpr  = Expression.LessThan(scheduledTimeValue, nowValue);

    return Expression.Lambda<Func<TaskEntry, bool>>(scheduledTestExpr, taskEntryExpr);
}
  • Related