C# - Dynamic Linq - Generic Searching - DateTime

时间:2015-11-12 11:07:47

标签: c# linq datetime generics

Good morning everyone, I have a question about linq to sql. Specifically "Dynamic Linq". I'm trying to create a search function where the user can enter any string and it'd filter all fields including DateTime fields.

So say the DateTime stored is "10/11/2015", when the user types in "10" I would like the record to return.

So something like:

x=> x.dateTime.ToString("dd/mm/yyyy").Contains("10")

but that doesn't work because sql doesn't have a ToString method.

To make this problem more interesting, all of this is generic. So I receive the properties that must be searched as a list of strings, I receive the type as T and I receive the search string as a string.

So heres an example of how I would write the search expression if I were just looking for "10" in the property "dateTime", that is, if T were a generic Type.

ConstantExpression searchArgument = Expression.Constant("10");
ParameterExpression param = Expression.Parameter(typeof(T), "x");

// Get Property, even if nested property.
Expression property = "dateTime".Split('.').Aggregate<string, Expression>(param, Expression.Property);

// Get Contains method for property type
MethodInfo containsMethod = typeof(String).GetMethod("Contains");

// Convert the property if necessary.
MethodInfo convertMethod = null;
if (TypeExtensions.IsNumericType(property.Type))
{
    convertMethod = typeof(SqlFunctions).GetMethod("StringConvert", new[] { typeof(double?) });
    if (convertMethod != null)
    {
        property = Expression.Call(convertMethod, Expression.Convert(property, typeof(double?)));
    }
}
else if (property.Type == typeof(DateTime))
{
    throw new NotImplementedException();
    // TODO - How do I write a convertion method here to convert the DateTime property to a string as "dd/mm/yyyy"?
    convertMethod = null;
    if (convertMethod != null)
    {
        property = Expression.Call(convertMethod, Expression.Convert(property, typeof(DateTime?)));
    }
}

MethodCallExpression fieldExpression = Expression.Call(property, containsMethod, searchArgument);

// Create the contains expression
Expression<Func<T, bool>> searchExpression = Expression.Lambda<Func<T, bool>>(fieldExpression, param);

This works for strings and numbers but not for DateTimes, can anyone help? Thanks in advance!

2 个答案:

答案 0 :(得分:1)

I'd need to doublecheck this, but according to https://msdn.microsoft.com/en-us/library/bb738681.aspx , Day, Month and Year should work, so instead of doing one comparison, you could do something like:

(x.dateTime.Day.ToString().Contains("10") || 
 x.dateTime.Month.ToString().Contains("10") ||
 x.dateTime.Year.ToString().Contains("10"))

I recall EF understands ToString() on integers, though I'm not sure, but if it doesn't, use SqlFunctions.StringConvert above, instead of ToString()


Or you could make the string yourself using SqlFunctions instead of calling ToString, something like:

(SqlFunctions.DateName("dd", x) + "/" +
 SqlFunctions.StringConvert((double)SqlFunctions.DatePart("m", x)).Trim() + "/" +
 SqlFunctions.DateName("yyyy", x)
).Contains("10")

答案 1 :(得分:0)

You can also compare by components, check if the day, month or year is equal to the variable your are passing. I dont know if you would also like. for example, if the user puts like "1" return all records with a date that contains 1, but that i dont advise either, you would be returning a lot of records if your database has some dimension