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, 

        //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),
                                                   new Type[] { source.ElementType },
                                                   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...