I recently stumpled upon the problem to dynamically create Linq expressions. Most examples I found deal with the rather simple task, just comparing one property of a given database entity with a single parameter.
I would like to compare related object with a specific property. I already create a contains expression. But I would like to create a dynamic doesn't contains expression.
Here is the specific code with the explicit LINQ query I would to reproduce in generic form.
var schools = new List<School>
{
new School("School1") { Students = new List<Student>() { new Student("Student1"), new Student("Student2") }},
new School("School1") { Students = new List<Student>() { new Student("Student1"), new Student("Student2") }},
new School("School2") { Students = new List<Student>() { new Student("Student3"), new Student("Student4") }},
new School("School3") { Students = new List<Student>() { new Student("Student3"), new Student("Student5") }},
};
string searchValue = "Student3";
// Explicit query (will be the result)
var query = schools.Where(x => !x.Students.Any(y => y.Name.Contains(searchValue)));
Where "Students" is of the type List and the property "Name" is of the type string. "Schools" contains the Students list.
I tried something like this but I'm not sure is the best practice to achieve.
public class NotAnyContainsClass
{
private static readonly MethodInfo MethodContains = typeof(Enumerable).GetMethods(
BindingFlags.Static | BindingFlags.Public)
.Single(m => m.Name == nameof(Enumerable.Contains) && m.GetParameters().Length == 2);
private static readonly MethodInfo MethodAny = typeof(Enumerable).GetMethods(
BindingFlags.Static | BindingFlags.Public)
.Single(m => m.Name == nameof(Enumerable.Any) && m.GetParameters().Length == 2);
private static readonly MethodInfo EnumerableCastMethod = typeof(Enumerable).GetMethod("Cast");
private static readonly MethodInfo GenericContainsMethod = MethodContains.MakeGenericMethod(typeof(object));
private static readonly MethodInfo GenericAnyMethod = MethodAny.MakeGenericMethod(typeof(object));
public Expression CreateExpression(string searchString)
{
//Query.<OuterList>.Where(x => !x.<InnerList>.Any(y => y.Name.Contains(searchValue)));
//...
}
}
And the caller would be
var operation = new NotAnyContainsClass();
var expression = operation.CreateExpression(searchValue, /* I think need more parameters */);
var query = expression(schools);
Is it possible to build a Linq expression like this dynamically ? After it will be used for generate SQL query with Linq.