SearchExtensions : Search extension method for multiple properties against multiple terms
Now available as a nuget package. Search for 'SearchExtensions' or run the following:
PM> Install-Package NinjaNye.SearchExtensions
Source code can be found here: https://github.com/ninjanye/searchextensions
I've recently updated my IQueryable search extension method library to include a search method that allows searching multiple terms against multiple properties. Here's the code with some example output when connected to sql
The code
public static class QueryableExtensions
{
/// <summary>
/// Search multiple properties for multiple search terms
/// </summary>
/// <param name="source">Source data to query</param>
/// <param name="searchTerms">search term to look for</param>
/// <param name="stringProperties">properties to search against</param>
/// <returns>Collection of records matching the search term</returns>
public static IQueryable<T> Search<T>(this IQueryable<T> source,
IList<string> searchTerms,
params Expression<Func<T, string>>[] stringProperties)
{
if (!searchTerms.Any())
{
return source;
}
// The below is the equivalent lamda that is being constructed:
// source.Where(x => x.[property1].Contains(searchTerm1)
// || x.[property1].Contains(searchTerm2)
// || x.[property2].Contains(searchTerm1)
// || x.[property2].Contains(searchTerm2)
// || x.[property3].Contains(searchTerm1)
// || x.[property3].Contains(searchTerm2)...)
//Variable to hold merged 'OR' expression
Expression orExpression = null;
//Retrieve first parameter to use accross all expressions
var singleParameter = stringProperties[0].Parameters.Single();
foreach (var searchTerm in searchTerms)
{
//Create expression to represent x.[property].Contains(searchTerm)
ConstantExpression searchTermExpression = Expression.Constant(searchTerm);
//Build a contains expression for each property
foreach (var stringProperty in stringProperties)
{
//Syncronize single parameter accross each property
var swappedParamExpression = SwapExpressionVisitor.Swap(stringProperty, stringProperty.Parameters.Single(), singleParameter);
//Build expression to represent x.[propertyX].Contains(searchTerm)
var containsExpression = BuildContainsExpression(swappedParamExpression, searchTermExpression);
orExpression = BuildOrExpression(orExpression, containsExpression);
}
}
var completeExpression = Expression.Lambda<Func<T, bool>>(orExpression, singleParameter);
return source.Where(completeExpression);
}
The helper methods and SwapExpressionVisitor
can all be found on my SearchExtension github project.
Using it
The new extension method can be used as follows (given source
variable is of type IQueryable<Person>
with FirstName
and Nickname
string properties)
var searchTerms = new List<string>{ "john", "fred", "barry" };
var result = source.Search(searchTerms, p => p.FirstName,
p => p.Nickname).ToList();
The result
When using a sql provider, the above produces the following sql
SELECT [Columns]
FROM [dbo].[People] AS [Extent1]
WHERE ([Extent1].[FirstName] LIKE N'%john%')
OR ([Extent1].[Nickname] LIKE N'%john%')
OR ([Extent1].[FirstName] LIKE N'%fred%')
OR ([Extent1].[Nickname] LIKE N'%fred%')
OR ([Extent1].[FirstName] LIKE N'%barry%')
OR ([Extent1].[Nickname] LIKE N'%barry%')
Perfect...
Don't forget to download the package via nuget. I'll be releasing regular updates so please get in touch if you would like particular functionality added to the library.
If you found this post useful please share using the icons above or get in touch if you have any questions.
Very cool! Thought about building something similar a few times but never had the time to do so. Now i just have to type nuget. Great work
Hi Alex,
Thanks for your support. Stay tuned as I plan to extend SearchExtensions to accommodate some additional search functionality