Dynamic Linq Queries - Contains Operator
Ayende just posted about dynamic LINQ queries and how not to write them.
On BackgroundMotion we were using Linq to SQL and needed the Contains operator. Unfortunately, on the CTP we were using the Contains operator wasn’t implemented by the Linq to SQL provider. Happily however, we were able to emulate it by dynamically building the required query. Here is the code:
public static class LinqContainsPredicateBuilder { public static Expression<Func<T, bool>> Build<T, S>(ICollection<S> collection, string targetProperty) { Invariant.ArgumentNotEmpty(collection, "collection"); Invariant.ArgumentNotEmpty(targetProperty, "targetProperty"); Expression completeExpression = null; ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "t"); foreach (S item in collection) { Expression nextExpression = Expression.EQ ( Expression.Property(parameterExpression, typeof(T).GetProperty(targetProperty)), Expression.Constant(item) ); completeExpression = (completeExpression != null) ? Expression.OrElse(completeExpression, nextExpression) : nextExpression; } return (Expression<Func<T, bool>>)QueryExpression.Lambda(completeExpression, parameterExpression); } }
For example, let’s say we are interested in finding all the Tag objects in the repository corresponding to a list of tags entered by a user. We could do this like so:
IList<string> candidateTags = new List<string>(); candidateTags.Add("Foo"); candidateTags.Add("Bar"); candidateTags.Add("Baz"); Expression<Func<T, bool>> expr = LinqContainsPredicateBuilder.Build<Tag, string>(candidateTags , "Value"); // now use the expression in a LINQ query...
This code will return any Tag objects that have a Value property matching any of the elements in the candidateTags list.
Being able to do this kind of thing is powerful and compelling feature of LINQ.
Trackbacks
Use this link to trackback from your own site.



Thanks. Just what I needed!
By the way, your Invariant class looks interesting. Have you tried doing an expression-based version, like this:
Invariant.ArgumentNotEmpty( () => collection);
I would imagine that you could get the name from the expression. It’s just a shame it can’t be written like this:
Invariant.ArgumentNotEmpty( => collection);
but MS insist on having the empty parentheses.
Guess it would run slower though, since would have to compile the expression….