C# generic search extension method for IQueryable
less than a minute read
Now available as a nuget package. Search for 'SearchExtensions' or run the following:
<p class="nuget-badge"><code>PM> Install-Package NinjaNye.SearchExtensions</code></p> **Source code can be found here: [https://github.com/ninjanye/searchextensions](https://github.com/ninjanye/searchextensions)**Following on from my previous post on creating a generic repository method, I decided to take it a step further and create an generic search extension method to perform the same task.
Here is the code:
public static class QueryableExtensions
{
    public static IQueryable<T> Search<T>(this IQueryable<T> source, Expression<Func<T, string>> stringProperty, string searchTerm)
    {
        if (String.IsNullOrEmpty(searchTerm))
        {
            return source;
        }
        // The below represents the following lamda:
        // source.Where(x => x.[property] != null
        //                && x.[property].Contains(searchTerm))
        //Create expression to represent x.[property] != null
        var isNotNullExpression = Expression.NotEqual(stringProperty.Body, 
                                                      Expression.Constant(null));
        //Create expression to represent x.[property].Contains(searchTerm)
        var searchTermExpression = Expression.Constant(searchTerm);
        var checkContainsExpression = Expression.Call(stringProperty.Body, typeof(string).GetMethod("Contains"), searchTermExpression);
        //Join not null and contains expressions
        var notNullAndContainsExpression = Expression.AndAlso(isNotNullExpression, checkContainsExpression);
        var methodCallExpression = Expression.Call(typeof(Queryable),
                                                   "Where",
                                                   new Type[] { source.ElementType },
                                                   source.Expression,
                                                   Expression.Lambda<Func<T, bool>>(notNullAndContainsExpression, stringProperty.Parameters));
        return source.Provider.CreateQuery<T>(methodCallExpression);
    }
}
Performing the following code against a DBContext (connected to a sql db):
string searchTerm = "test";
var results = context.Clubs.Search(club => club.Name, searchTerm).ToList();
Which produces the following SQL:
SELECT [Extent1].[Id] AS [Id], 
       [Extent1].[Name] AS [Name] 
FROM   [dbo].[Clubs] AS [Extent1]
WHERE  ([Extent1].[Name] IS NOT NULL) 
  AND  ([Extent1].[Name] LIKE N'%test%')
  
My next goal is to create an extension method that allows the user to pass multiple properties. The results will then match any of the supplied properties. Stay tuned...