John Nye

Agile software developer

My name is John Nye. I am a developer from Essex, working in London. I specialize in C#, ASP.NET MVC, Test driven development (TDD), Entity Framework, HTML5, Javascript and JQuery. I have built this blog from scratch using ASP.NET MVC 4, Entity Framework code first and markdowndeep.

If you have any feedback on my blog or just want to strike up a conversation I'd love to hear from you. You can get in touch with me via twitter @ninjanye or by emailing using the links in the header.

Check out my latest posts below or use my tag cloud for previous posts on a specific subjects

SearchExtensions now supports searching of child collections for IQueryable

You can now perform child collection searches on IQueryable objects which will get translated and run on the data source server returning only the filtered records.

String searching

The functionality allows for the following to be performed on the data provider and not in memory

var shops = context.Shops.SearchChildren(s => s.Products)
                         .With(p => p.Name)
                         .Containing("ball");

The above returns shops that contain any product that has the term "ball" in it's Name field.

The above will send the following SQL when using LinqToEntities

SELECT [Extent1].[Id] AS [Id]
  -- Additional columns --        
FROM [dbo].[Shops] AS [Extent1]
WHERE EXISTS (
  SELECT 1 AS [C1]
  FROM [dbo].[Products] AS [Extent2]
  WHERE ([Extent1].[Id] = [Extent2].[Shop_Id])
    AND ([Extent2].[Name] LIKE N'%ball%')
)

Support is also in place for searching multiple properties and multiple values

var shops = context.Shops.SearchChildren(s => s.Products)
                         .With(p => p.Name, p => p.Desc)
                         .Containing("ball", "balls");

Additional string comparisons

All the usual string comparisons that you expect from SearchExtensions are also supported for searching child records:

  • .StartsWith() - property starts with any of the given terms
  • .EndsWith() - property ends with any of the given terms
  • .EqualTo() - property is equal to any of the given terms
  • .Containing() - property contains any of the given terms
  • .ContainingAll() - property contains all of the given terms

Support for non string filtering

Support has also been added to allow searching child collections for matches on other types. The following example returns shops who have products with a price between 10,000 and 100,000:

var shops = context.Shops.SearchChildren(s => s.Products)
                         .With(p => p.Price, p => p.RRP)
                         .Between(10000, 100000);

Both the examples so far will return a collection of Shops where any of it's products match the given criteria.

The equivalent of the above without utilising SearchExtensions is as follows:

var shops = context.Shops.Where(s => s.Products.Any(p =>
                              (p.Price > 10000 && p.Price < 100000)
                           || (p.RRP > 10000 && p.RRP < 100000)));

All the usual non string comparisons have also been implemented for IQueryable searching:

  • .GreaterThan()
  • .GreaterThanOrEqualTo()
  • .LessThan()
  • .LessThanOrEqualTo()
  • .Between()

Method Chaining

As is the norm with SearchExtensions, It is also possible to chain your search criteria together in order to create more complex filtering:

var result = context.Countries.SearchChildren(x => x.Cities)
                    .With(c => Name, c => c.LocalName)
                    .StartsWith("A", "E", "I", "O", "U")
                    .EndsWith("S", "T", "U", "V", "W");

To read more about SearchExtensions, please visit ninjanye.github.io/SearchExtensions/


Thanks again to @bzbetty for getting in touch via a github issues and creating this feature request

If you have a new feature request, please get in touch by adding a comment below, contact me on twitter (@ninjanye) or you can raise an issue on the github project page

To install SearchExtensions, you can either install it via the Nuget Package manager or by using the following in the package manager console

PM> Install-Package NinjaNye.SearchExtensions

Search child collections

I received a request from a user who wondered if SearchExtensions could do something like the functionality described as follows:

Given I have a collection of Shops
I want to return all Shops that stock a Product with a Name containing "foot"

This feature is now available in the latest release via a new method, .SearchChildren(). Currently this is only available for LinqToObjects, not LinqToEntities (yet):

var shops = allShops.SearchChildren(s => s.Products)
                    .With(p => p.Name, p => p.Desc)
                    .Containing("foot", "feet");

The above returns shops that contain any product that has the term "foot" or "feet" in it's Name or Description fields.

Support has also been added to allow searching child collections for matches on other types. The following example returns shops who have products with a price greater than 10,000:

var shops = allShops.SearchChildren(s => s.Products)
                    .With(p => p.Price)
                    .GreaterThan(10000m);

Both the above examples will return a collection of Shops where any of it's products match the given criteria.

The equivalent of the first example in LinqToObjects would be something like:

var shops = allShops.Where(s => s.Products.Any(p => p.Name.Contains("foot")
                                                 || p.Name.Contains("feet")
                                                 || p.Desc.Contains("foot")
                                                 || p.Desc.Contains("feet")))

Additional comparisons available

Other string comparisons available for normal searching are also available for searching children, such as:

  • .StartsWith() - property starts with any of the given terms
  • .EndsWith() - property ends with any of the given terms
  • .EqualTo() - property is equal to any of the given terms
  • .Containing() - property contains any of the given terms
  • .ContainingAll() - property contains all of the given terms

Non string comparisons have also been implemented when searching child collections:

  • .GreaterThan()
  • .GreaterThanOrEqualTo()
  • .LessThan()
  • .LessThanOrEqualTo()

Searching across multiple children

The ability to search across multiple children (of the same type) is also supported. Consider the following (contrived) example:

I want to return all `parents` who have a `Son` OR a `Daughter` with a `Forename` or `Nickname` beginning with 'A', 'E', 'I', 'O' or 'U'

The Model

public class Parent
{
  public IEnumerable<Child> Sons { get; private set; }
  public IEnumerable<Child> Daughters { get; private set; }
}

public class Child
{
  public int Age {get; private set;}
  public string Forename {get; private set;}
  public string Nickname {get; private set;}
  public string Surname {get; private set;}
}

Performing the search

Given a list of parents I could now do the following:

var result = parents.SearchChildren(p => p.Sons, p => p.Daughters)
                    .With(c => Forname, c => c.NickName)
                    .StartsWith("A", "E", "I", "O", "U");

The result

The result of this search is a collection of parents who have a son or a daughter with a forename or surname beginning with a vowel.

Note that all of a parents children will still be present for each parent.

The filter is performed against the parent but the conditions are against the children.


Thanks to @bzbetty for getting in touch via a github issues.

This feature was not something I would have completed without his request as I had not seen or envisaged a need for it.

If you have a new feature request, please get in touch by adding a comment below, contact me on twitter (@ninjanye) or you can raise an issue on the github project page

To install SearchExtensions, you can either install it via the Nuget Package manager or by using the following in the package manager console

PM> Install-Package NinjaNye.SearchExtensions

Search text for whole word matches

I recently received a request from a user to looking to be able to search for terms whilst not returning partial matches. For instance, given I am searching for the word "tension", I would not expect "extension" to be returned

In version 1.6 it is now possible to restrict your search to only return records where whole words are matched.

var result = data.Search(x => Name)
                 .Matching(SearchType.WholeWords)
                 .Containing("tension");

We can also mix the search types. The following example matches "tension" against whole words only but then reverts a search for "search" to match against any occurrence,

var result = data.Search(x => Name)
                 .Matching(SearchType.WholeWords)
                 .Containing("tension");
                 .Matching(SearchType.AnyOccurrence)
                 .Containing("search");

The above code will return "tension research" but would not return "extension research"

This feature is also available to .StartsWith() and .EndsWith() methods.


Thanks to Rob for getting in touch via a previous post.
This feature has come about purely because he got in touch.

If you have a new feature request, please get in touch by adding a comment below, contact me on twitter (@ninjanye) or you can raise an issue on the github project page

PM> Install-Package NinjaNye.SearchExtensions