This project is avaliable for download as a nuget package
PM> Install-Package NinjaNye.SearchExtensions
String Searching
String searching allows you to search any number of
string
properties. Searches can be made against any
number of search terms or against any number of string properties.
Methods
The following methods are available to both
IQueryable
data and IEnumerable
data. Each
method will return records where any of the supplied properties are
matched by the rules below:
-
Containing
- target property contains any of the search terms provided. -
ContainingAll
- target property contains all of the search terms provided. -
EqualTo
- target property equals any of the search terms provided. -
StartsWith
- target property starts with any of the search terms provided. -
EndsWith
- target property ends with any of the search terms provided. -
ToRanked
- transforms the results of aContaining
search into a ranked result.
IEnumerable
data collections have the following
additional methods available use:
-
SetCulture
- Sets the string comparison culture with which to perform searches
Performing Containing
searches
Search for a single search term within a single property
var result = queryableData.Search(x => x.Property1)
.Containing("searchTerm");
Search for a single search term within multiple properties
var result = queryableData.Search(x => x.Property1,
x => x.Property2,
x => x.Property3)
.Containing("searchTerm");
Search for multiple search terms within a single property
var result = queryableData.Search(x => x.Property1)
.Containing("search", "term");
Search for multiple search terms within multiple properties
var result = queryableData.Search(x => x.Property1,
x => x.Property2,
x => x.Property3)
.Containing("searchTerm1",
"searchTerm2",
"searchTerm3");
Performing Containing
AND searches
Search where a single property contains a
single search term
AND contains another single search term
var result = queryableData.Search(x => x.Property1)
.Containing("searchTerm1")
.Containing("searchTerm2");
Search where a single search term exists within in
Property1 OR Property2
AND single search term exists within in Property3 OR
Property4
var result = queryableData.Search(x => x.Property1, x => x.Property2)
.Containing("searchTerm")
.Search(x => x.Property3, x => x.Property4)
.Containing("searchTerm");
Search where a single search term exists in Property1
OR Property2
AND any of the multiple search terms exist within a
Property3
var result = queryableData.Search(x => x.Property1, x => x.Property2)
.Containing("searchTerm")
.Search(x => x.Property3)
.Containing("another", "term");
Performing ContainingAll
searches
Search where all search terms are within a single property
var result = queryableData.Search(x => x.Property1)
.ContainingAll("search", "term");
Search where all search terms exist across multiple properties
var result = queryableData.Search(x => x.Property1,
x => x.Property2,
x => x.Property3)
.ContainingAll("search", "term");
Performing EqualTo
searches
Search where a single property equals a single search term
var result = queryableData.Search(x => x.Property1)
.EqualTo("searchTerm");
Search where any one of multiple properties is equal to a single search term
var result = queryableData.Search(x => x.Property1,
x => x.Property2,
x => x.Property3)
.EqualTo("searchTerm");
Search where a single property is equal to any one of multiple search terms
var result = queryableData.Search(x => x.Property1)
.EqualTo("search", "term");
Search where any one of multiple properties is equal to any one of multiple search terms
var result = queryableData.Search(x => x.Property1,
x => x.Property2,
x => x.Property3)
.EqualTo("searchTerm1",
"searchTerm2",
"searchTerm3");
Performing StartsWith
searches
Search where a single property starts with a single search term
var result = queryableData.Search(x => x.Property1)
.StartsWith("searchTerm");
Search where any one of multiple properties starts with to a single search term
var result = queryableData.Search(x => x.Property1,
x => x.Property2,
x => x.Property3)
.StartsWith("searchTerm");
Search where a single property starts with any one of multiple search terms
var result = queryableData.Search(x => x.Property1)
.StartsWith("search", "term");
Search where any one of multiple properties starts with any one of multiple search terms
var result = queryableData.Search(x => x.Property1,
x => x.Property2,
x => x.Property3)
.StartsWith("searchTerm1",
"searchTerm2",
"searchTerm3");
Performing EndsWith
searches
Search where a single property ends with a single search term
var result = queryableData.Search(x => x.Property1)
.EndsWith("searchTerm");
Search where any one of multiple properties ends with a single search term
var result = queryableData.Search(x => x.Property1, x => x.Property2,
x => x.Property3)
.EndsWith("searchTerm");
Search where a single property ends with any one of multiple search terms
var result = queryableData.Search(x => x.Property1)
.EndsWith("search", "term", "test");
Search where any one of multiple properties starts with any one of multiple search terms
var result = queryableData.Search(x => x.Property1, x => x.Property2,
x => x.Property3)
.EndsWith("searchTerm1", "searchTerm2", "searchTerm3");
Ranked Searches
As well as returning the matched items, a Ranked Search also returns a hit count for each item in the form of an IRanked result. This enables you to order by hit count to retrieve the most relevant search results.
IRanked<T>
result
An IRanked result is simply defined as follows:
public interface IRanked<out T>
{
int Hits { get; }
T Item { get; }
}
This is returned using the ToRanked()
method:
RankedSearch for a single search term within a single property
var result = queryableData.Search(x => x.Property1)
.Containing("searchTerm")
.ToRanked();
RankedSearch for a single search term within multiple properties
var result = queryableData.Search(x => x.Property1,
x => x.Property2,
x => x.Property3)
.Containing("searchTerm")
.ToRanked();
RankedSearch for multiple search terms within a single property
var result = queryableData.Search(x => x.Property1)
.Containing("searchTerm1",
"searchTerm2",
"searchTerm3")
.ToRanked();
RankedSearch for multiple search terms within multiple properties
var result = queryableData.Search(x => x.Property1, x => x.Property2)
.Containing("searchTerm1",
"searchTerm2",
"searchTerm3")
.ToRanked();
Retrieve most relevant search results
Using ranked search you can now easily order your search results by
the most relevant. This following example assumes we have a list of
User
which has FirstName
,
LastName
and MiddleName
string properties.
In this example we want to match on those with "John" in their name
and retrieve the top 10 results.
var result = context.Users.Search(x => x.FirstName,
x => x.LastName,
x => x.MiddleName)
.Containing("John")
.ToRanked()
// Order by Hits property of IRanked<User>
.OrderByDescending(r => r.Hits)
.Take(10);
Mixing it up
We can also mix it up with the other fluent API methods
var result = context.Users.Search(x => x.FirstName,
x => x.LastName,
x => x.MiddleName)
.StartsWith("john")
.Containing("smith")
.ToRanked()
// Order by Hits property of IRanked<User>
.OrderByDescending(r => r.Hits)
.Take(10);
ToRanked()
method uses the search terms of the
Containing()
method combined with the properties
to search to build its hit count.
Performing IEnumerable searches
The above methods can all be performed on bothIQueryable
collections andIEnumerable
collections.
The important thing to remember when performing an in memory search is
to set the culture to the type of string comparison you wish to
perform.
If SetCulture
is not specified,
StringComparison.CurrentCulture
is used.
var result = enumerableData.Search(x => x.Property1)
// Set culture for comparison
.SetCulture(StringComparison.OrdinalIgnoreCase)
.StartsWith("abc")
.EndsWith("xyz")
.Containing("mno");
It is also possible to switch the StringComparison
culture context multiple times
var result = enumerableData.Search(x => x.Property1)
.SetCulture(StringComparison.OrdinalIgnoreCase)
.StartsWith("abc") // Uses OrdinalIgnoreCase
.SetCulture(StringComparison.Ordinal)
.EndsWith("xyz") // Uses Ordinal
.SetCulture(StringComparison.CurrentCulture)
.Containing("mno"); // Uses CurrentCulture
Combining instructions
With SearchExtensions you can also combine search actions. For instance:
Search where a single property
starts with
a single search term
AND containing
a single search term
var result = queryableData.Search(x => x.Property1)
.StartsWith("abc")
.Containing("mno");
The ability to pass multiple search terms to any of the action methods still remains
var result = queryableData.Search(x => x.Property1, x => x.Property2)
.StartsWith("abc", "ninja")
.Containing("xyz", "extensions")
Note: CombiningIEnumerable
methods onIQueryable
data will cause the data to be brought in to memory at the point at which the first enumerable action is taken.
If you have any new feature requests, questions, or comments, please get in touch, either, via my website, through twitter: @ninjanye or by creating an issue through the projects github page .