如何在动态 LINQ 中使用包含时将强制转换动态键入为字符串
本文关键字:动态 转换 字符串 包含时 LINQ | 更新日期: 2023-09-27 18:34:49
我想使用动态 LINQ 查询来搜索类中所有属性中的一些文本。 我正在使用以下函数来创建表达式。我正在将属性名称和搜索文本传递给该方法。 在该方法中,如果属性类型为字符串,则它工作正常。如果属性类型为 int、日期时间、GUID。然后它不起作用。
众所周知,包含方法仅适用于元素数组或字符串。我认为属性的值应该类型转换为字符串。那么怎么做呢?带有解释的解决方案是完整的帮助。
我从中收集了代码。
public static Expression<Func<T, bool>> ContainsExp<T>(string propertyName, string contains)
{
var parameterExp = Expression.Parameter(typeof(T), "type");
var propertyExp = Expression.Property(parameterExp, propertyName);
MethodInfo method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
var someValue = Expression.Constant(contains, typeof(string));
var containsMethodExp = Expression.Call(propertyExp, method, someValue);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}
好吧,您可能知道在 linq to 实体中使用 ToString()
是不可能的。
所以下面的问题是:如何将其他类型的转换为字符串。
对于数值,您有 SqlFunctions.StringConvert
,但它只有 double?
和 decimal?
的重载
对于日期时间,您可能会在DateTime
上应用SqlFunctions.DatePart
后找到使用SqlFunctions.StringConvert
的内容(这可能意味着至少 3 次调用SqlFunctions.DatePart
,用于年、月、日(
对于Guid,我认为没有办法直接做到这一点。一种方法(在数据库级别,如果使用 Sql Server(可能是具有计算列。计算列可以存储 GUID 的 varchar 转换表示形式。也许有更好的方法。
无论如何,这里至少有一个应该适用于integer
和string
的示例:
public static Expression<Func<T, bool>> ContainsExp<T>(string propertyName, string contains)
{
//first, get the type of your property
var propertyType = typeof(T).GetProperty(propertyName).PropertyType;
//no change
var parameterExp = Expression.Parameter(typeof (T), "type");
Expression propertyExp = Expression.Property(parameterExp, propertyName);
//if property's type is int
if (propertyType == typeof (int))
{
//convert your Expression to a nullable double (or nullable decimal),
//so that you can use SqlFunctions.StringConvert
propertyExp = Expression.Convert(propertyExp, typeof (double?));
//get the SqlFunctions.StringConvert method for nullable double
var stringConvertMethod = typeof (SqlFunctions).GetMethod("StringConvert", new[] {typeof (double?)});
//call StringConvert on your converted expression
propertyExp = Expression.Call(stringConvertMethod , propertyExp);
}
//no change
var method = typeof (string).GetMethod("Contains", new[] {typeof (string)});
var someValue = Expression.Constant(contains, typeof (string));
var containsMethodExp = Expression.Call(propertyExp, method, someValue);
return Expression.Lambda<Func<T, bool>>(containsMethodExp, parameterExp);
}
public static IQueryable<T> FieldsContains<T>(this IQueryable<T> query, List<string> fileds, string searchValue)
{
Expression predicate = null;
var parameterExpression = Expression.Parameter(typeof(T), "type");
foreach (string field in fileds)
{
var next = GetFieldContainsExpression<T>(parameterExpression, field, searchValue);
if (predicate == null)
{
predicate = next;
}
else
{
predicate = Expression.Or(predicate, next);
}
}
var lambda = Expression.Lambda<Func<T, bool>>(predicate, parameterExpression);
return query.Where(lambda);
}
private static Expression GetFieldContainsExpression<T>(ParameterExpression parameterExpression, string field, string value)
{
var propertyType = typeof(T).GetProperty(field).PropertyType;
Expression propertyExpression = Expression.Property(parameterExpression, field);
var filterValue = Expression.Constant(value);
var method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
//call toString first to ignore type errors(datetime, int ...)
var toStringExpression = Expression.Call(propertyExpression, "ToString", Type.EmptyTypes);
var containsExpression = Expression.Call(toStringExpression, method, filterValue);
return containsExpression;
}