我正在使用以下文章中的代码来动态构建LINQ查询。
http://www.codeproject.com/Tips/582450/Build-Where-Clause-Dynamically-in-Linq
虽然互联网上有更好的建议,但直到现在它才符合我的目的,而且Fitim Skenderi的代码也很容易理解。
我现在需要通过连接两个或多个表来在运行时构建查询。我在网上找不到任何例子。
我的代码:
public enum Op
{
IsEqualTo,
IsGreaterThan,
IsLessThan,
IsGreaterThanOrEqualTo,
IsLessThanOrEqualTo,
Contains,
StartsWith,
EndsWith
}
public class Filter
{
public string PropertyName { get; set; }
public Op Operation { get; set; }
public object Value { get; set; }
}
public static class ExpressionBuilder
{
private static MethodInfo containsMethod = typeof(string).GetMethod("Contains");
private static MethodInfo startsWithMethod = typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) });
private static MethodInfo endsWithMethod = typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) });
public static Expression<Func<T, bool>> GetExpression<T>(IList<Filter> filters, bool matchAll)
{
if (filters.Count == 0)
return null;
ParameterExpression param = Expression.Parameter(typeof(T), "t");
Expression exp = null;
if (filters.Count == 1)
exp = GetExpression<T>(param, filters[0]);
else if (filters.Count == 2)
exp = GetExpression<T>(param, filters[0], filters[1], matchAll);
else
{
while (filters.Count > 0)
{
var f1 = filters[0];
var f2 = filters[1];
if (exp == null)
exp = GetExpression<T>(param, filters[0], filters[1], matchAll);
else
{
if(matchAll)
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0], filters[1], matchAll));
else
exp = Expression.OrElse(exp, GetExpression<T>(param, filters[0], filters[1], matchAll));
}
filters.Remove(f1);
filters.Remove(f2);
if (filters.Count == 1)
{
if(matchAll)
exp = Expression.AndAlso(exp, GetExpression<T>(param, filters[0]));
else
exp = Expression.OrElse(exp, GetExpression<T>(param, filters[0]));
filters.RemoveAt(0);
}
}
}
return Expression.Lambda<Func<T, bool>>(exp, param);
}
private static Expression GetExpression<T>(ParameterExpression param, Filter filter)
{
MemberExpression member = Expression.Property(param, filter.PropertyName);
UnaryExpression constant = null;
if (member.Type == typeof(Decimal?))
{
constant = Expression.Convert(Expression.Constant(Decimal.Parse(filter.Value.ToString())), member.Type);
}
else if (member.Type == typeof(DateTime?))
{
constant = Expression.Convert(Expression.Constant(DateTime.Parse(filter.Value.ToString())), member.Type);
}
else if (member.Type == typeof(int?))
{
constant = Expression.Convert(Expression.Constant(int.Parse(filter.Value.ToString())), member.Type);
}
else
{
if (filter.Value.GetType() != member.Type)
{
object result = Convert.ChangeType(filter.Value, member.Type);
constant = Expression.Convert(Expression.Constant(result), member.Type);
}
else
{
constant = Expression.Convert(Expression.Constant(filter.Value), member.Type);
}
}
switch (filter.Operation)
{
case Op.IsEqualTo:
return Expression.Equal(member, constant);
case Op.IsGreaterThan:
return Expression.GreaterThan(member, constant);
case Op.IsGreaterThanOrEqualTo:
return Expression.GreaterThanOrEqual(member, constant);
case Op.IsLessThan:
return Expression.LessThan(member, constant);
case Op.IsLessThanOrEqualTo:
return Expression.LessThanOrEqual(member, constant);
case Op.Contains:
return Expression.Call(member, containsMethod, constant);
case Op.StartsWith:
return Expression.Call(member, startsWithMethod, constant);
case Op.EndsWith:
return Expression.Call(member, endsWithMethod, constant);
}
return null;
}
private static BinaryExpression GetExpression<T> (ParameterExpression param, Filter filter1, Filter filter2, bool matchAll)
{
Expression bin1 = GetExpression<T>(param, filter1);
Expression bin2 = GetExpression<T>(param, filter2);
if(matchAll)
return Expression.AndAlso(bin1, bin2);
else
return Expression.OrElse(bin1, bin2);
}
}
最终用户选择(合同表),条件(=,&gt;,包含等)字段,并为要查询的每个选定字段输入值。根据最终用户的选择列表,创建filterCollection并生成查询。代码如下:
if (filterCollection.Count > 0)
{
var deleg = ExpressionBuilder.GetExpression<Contract>(filterCollection, true).Compile(); //true if all criteria are to be matched
contractList = ctx.Contracts.Where(deleg).ToList();
gridControl1.DataSource = contractList;
}
单表适用。但现在我需要让最终用户选择另一个名为Customer的表的字段,条件和值。 Customer表和Contract表由&#39; CustomerID&#39;链接。
如果用户想要查找名为“John&#39; John”的客户的所有合同,我该如何构建查询? (字段:名称,表格:客户)。任何帮助将不胜感激。