У меня есть Expression Tree
для создания динамического предложения where на основе критериев, которые пользователь выбирает для флажка.
Например: - Пользователь хочет найти: "test"
Пользователь выбирает
1. Проп1
2. Проп2
для объекта MyDBObject
Поисковый запрос будет выглядеть как
dbRecords.Where(r=> r.Prop1.Contains("test") || r.Prop2.Contains("test"))
Причина использования Expression Tree
заключается в том, что его можно использовать для любого неизвестного числа свойств неизвестного объекта.
У меня почти все работает, но я получаю Argument Expression is not valid
Кроме того, как можно инициализировать пустое логическое выражение, кроме использования «что-то, что оценивается как - истина / ложь»?Я читаю о них только несколько часов, так что, может быть, есть кое-что, чего я еще не видел.
public static Expression<Func<T, bool>> CreatePredicateFromCrtieriaAndSearchTerm<T>(List<string> checkedCriteria, string searchTerm)
{
// sample checked records
checkedCriteria = new[]
{
new { Name = "Prop1", DisplayValue = "Checkbox value 1" },
new { Name = "Prop2", DisplayValue = "Checkbox value 2" }
}
.Select(x => x.Name).ToList();
var param = Expression.Parameter(typeof(T), "record");
Expression oneEqualsOne = Expression.Equal(Expression.Constant(1), Expression.Constant(1));
// Creates (record => (1=1) AND ...)
Expression<Func<T, bool>> finalExpression = Expression.Lambda<Func<T, bool>>(oneEqualsOne, param);
Console.WriteLine(finalExpression);
try
{
// Iterate through properties, find selected props and create
// (record.SelectedProp1.Contains("searchTerm") || record.SelectedProp2.Contains("searchTerm") ... )
PropertyDescriptorCollection props = TypeDescriptor.GetProperties(typeof(T));
List<Expression> matchExpressions = new List<Expression>();
for (int i = 0; i < props.Count; i++)
{
PropertyDescriptor prop = props[i];
for (int j = 0; j < checkedCriteria.Count; j++)
{
if (prop.Name == checkedCriteria[j])
{
// add to where expression
Expression left = Expression.Property(param, prop.Name);
MethodInfo contains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
Expression right = Expression.Constant(searchTerm, searchTerm.GetType());
Expression matchExpression = Expression.Call(left, contains, right);
matchExpressions.Add(matchExpression);
}
}
}
// Creates (1=0 OR ... OR ...)
Expression currentPredicateBody = Expression.Equal(Expression.Constant(1), Expression.Constant(0));
foreach (var matchExpression in matchExpressions)
{
currentPredicateBody = Expression.MakeBinary(ExpressionType.OrElse, matchExpression, currentPredicateBody);
Console.WriteLine(currentPredicateBody);
}
// ( (1=0) || record.SelectedProp1.Contains("searchTerm") || record.SelectedProp2.Contains("searchTerm") )
if (matchExpressions.Count > 0)
{
oneEqualsOne = Expression.AndAlso(oneEqualsOne, currentPredicateBody);
Console.WriteLine(oneEqualsOne);
}
// Full expression:
// ( record => (1=1) AND ( (1=0) || record.SelectedProp1.Contains("searchTerm") || record.SelectedProp2.Contains("searchTerm") ))
finalExpression = Expression.Lambda<Func<T, bool>>(oneEqualsOne, new ParameterExpression[] { param });
Console.WriteLine(finalExpression);
}
catch (Exception ex)
{
throw new Exception(string.Format(@"Error occurred creating where predicate from checked criteria: {0}", ex.Message));
}
return finalExpression;
}
internal class MyDBObject
{
public int Id { get; set; }
public string Prop1 { get; set; }
public string Prop2 { get; set; }
public string Prop3 { get; set; }
public string Prop4 { get; set; }
public string Prop5 { get; set; }
public string Prop11 { get; set; }
public string Prop12 { get; set; }
public string Prop13 { get; set; }
public string Prop14 { get; set; }
public string Prop15 { get; set; }
public string Prop21 { get; set; }
public string Prop22 { get; set; }
public string Prop23 { get; set; }
public string Prop24 { get; set; }
public string Prop25 { get; set; }
}
public static void Main(string[] args)
{
List<MyDBObject> dbRecords = new List<MyDBObject>
{
new MyDBObject { Id = 1, Prop2 = "O1_P2", Prop3 = "O1_P3", Prop12 = "O1_P12", Prop15 = "O1_P15", Prop24 = "O1_P24", Prop25 = "O1_P25" },
new MyDBObject { Id = 2, Prop15 = "O2_P15", Prop21 = "test", Prop22 = "O2_P22", Prop23 = "O2_P23", Prop24 = "O2_P24", Prop25 = "O2_P25" },
new MyDBObject { Id = 3, Prop21 = "O3_P21", Prop22 = "O3_P22", Prop23 = "O3_P23", Prop24 = "test", Prop25 = "O3_P25" }
};
try
{
var predicate = CreatePredicateFromCrtieriaAndSearchTerm<MyDBObject>(null, "test");
var query = dbRecords.AsQueryable().Provider.CreateQuery<MyObject>(predicate);
List<MyObject> results = query.ToList();
foreach (var rs in results)
{
Console.WriteLine("Id: " + rs.Id);
}
}
catch (Exception ex)
{
Console.WriteLine("Error->> " + ex.Message);
}
}