我有IQueryable类型的数据集合,我抽象了一个方法,用作全场模糊查询,在开始时,我是逐个属性名称来编写的。如下代码:
private IQueryable<Tables1> FilterResult(string search, List<Tables1> dtResult)
{
IQueryable<Tables1> results = dtResult.AsQueryable();
results = results.Where(p => (
search == null || (
p.Name != null && p.Name.Contains(search) ||
p.age != null && p.age.ToString().Contains(search) ||
p.sex != null && p.sex.Contains(search) ||
p.content1 != null && p.content1.Contains(search) ||
p.content2 != null && p.content2.Contains(search) ||
p.content3 != null && p.content3.Contains(search)
)
));
return results;
}
但是,如果传入的List集合的类型发生变化,则写入,则所有物理属性都必须重新写入。所以我改变了T的类型:
private IQueryable<T> FilterResult(string search, List<T> dtResult,T t)
{
IQueryable<T> results = dtResult.AsQueryable();
//do something
return results;
}
这背后的想法是通过反射获得传入T类型的所有属性。然后通过表达式树构建Lambda表达式。
问题是如何构建'p =&gt; p.age.ToString()。通过表达式树包含(搜索)?
以下是完整的代码:
private IQueryable<T> FilterResult(string search, List<T> dtResult, T t)
{
List<Expression> tempExp = new List<Expression>();
var parameter = Expression.Parameter(typeof(T), "p");
foreach (var mi in t.GetType().GetProperties())
{
Expression left = Expression.Property(parameter, t.GetType().GetProperty(mi.Name));
Expression right = Expression.Constant(search, typeof(string));
MethodInfo method;
MethodCallExpression exp;
if (mi.PropertyType == typeof(Int32) || mi.PropertyType == typeof(Int64))
{
//this code is wrong
var exp1 = Expression.Call(Expression.Convert(left, typeof(string)), typeof(object).GetMethod("ToString"));
method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
exp = Expression.Call(exp1, method, right);
}
else
{
method = typeof(string).GetMethod("Contains", new[] { typeof(string) });
exp = Expression.Call(left, method, right);
}
tempExp.Add(exp);
}
Expression all = Expression.Or(Expression.Equal(Expression.Constant(search), null), tempExp[0]);
for (int i = 1; i < tempExp.Count; i++)
{
all = Expression.Or(all, tempExp[i]);
}
var lambda = Expression.Lambda<Func<T, bool>>(all, parameter);
var results = dtResult.Where(lambda.Compile()).AsQueryable(); ;
return results;
}
答案 0 :(得分:0)
我会说它可以更容易。我已将您的public class Tables
{
public int Age { get; set; }
public string Name { get; set; }
public string Content { get; set; }
}
public class Matcher
{
private static readonly PropertyInfo[] Properties = typeof(Tables).GetRuntimeProperties().ToArray();
public IQueryable<Tables> FilterResult(string search, List<Tables> dtResult)
{
if(search == null) //Consider using string.IsNullOrWhiteSpace(search) but I wasn't sure if you want to avoid searching for spaces
{
return dtResult.AsQueryable();
}
return dtResult.Where(p => IsMatch(p, search)).AsQueryable();
}
private static bool IsMatch(Tables tables, string search)
{
foreach (var propertyInfo in Properties)
{
var value = propertyInfo.GetValue(tables);
if (value != null && value.ToString().Contains(search))
{
return true;
}
}
return false;
}
}
模型简化为演示文稿。
class Program
{
public static void Main()
{
const string search = "Bob";
var matcher = new Matcher();
var items = new List<Tables>
{
new Tables {Content = string.Empty, Name = "Bob"}, //This will match
new Tables {Content = "Bob is the best guy.", Name = "Joe"}, //This will also match
new Tables {Content = "Something", Name = null} // This won't null name to verify that nothing unexpected will happen
};
var results = matcher.FilterResult( search, items );
foreach ( var result in results )
{
Console.WriteLine($"Matched the guy named {result.Name}");
}
Console.ReadKey();
}
}
我们可以在这里投入使用:
public class Matcher<T>
{
private static readonly PropertyInfo[] Properties = typeof(T).GetRuntimeProperties().ToArray();
public IQueryable<T> FilterResult(string search, List<T> items)
{
if ( search == null) //Consider using string.IsNullOrWhiteSpace(search) but I wasn't sure if you want to avoid searching for spaces
{
return items.AsQueryable();
}
return items.Where(p => IsMatch(p, search)).AsQueryable();
}
private static bool IsMatch(T item, string search)
{
foreach (var propertyInfo in Properties)
{
var value = propertyInfo.GetValue(item);
if (value != null && value.ToString().Contains(search))
{
return true;
}
}
return false;
}
}
编辑: 这是通用版本
config.vm.box = "ubuntu/precise64"