如何在动态 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 中使用包含时将强制转换动态键入为字符串

好吧,您可能知道在 linq to 实体中使用 ToString()是不可能的。

所以下面的问题是:如何将其他类型的转换为字符串。

对于数值,您有 SqlFunctions.StringConvert ,但它只有 double?decimal? 的重载

对于日期时间,您可能会在DateTime上应用SqlFunctions.DatePart后找到使用SqlFunctions.StringConvert的内容(这可能意味着至少 3 次调用SqlFunctions.DatePart,用于年、月、日(

对于Guid,我认为没有办法直接做到这一点。一种方法(在数据库级别,如果使用 Sql Server(可能是具有计算列。计算列可以存储 GUID 的 varchar 转换表示形式。也许有更好的方法。

无论如何,这里至少有一个应该适用于integerstring的示例:

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