This content is retired. See latest version here.

Last updated: Nov 16 2015

Extension methods

The Filter method provides a powerful way of filtering out certain matching documents by accepting an expression that returns a filter. These expressions are created easily by using a number of extension methods such as the Match method. These extension methods are however limited to operating on value types and strings but not on complex types. However, you can extend the filtering functionality in the following ways:

  • Create a custom extension method that returns a FilterExpression, this is the most common way.
  • Create extension methods that return an instance of the DelegateFilterBuilder class.

Returning a FilterExpression

A FilterExpression is an object that encapsulates an expression that returns a Filter. Once the query is executed the FilterExpression is found and replaced by the expression it encapsulates. Finally the field names in that expression is replaced with the corresponding field names on server side.

The following example shows two classes: Author and BlogPost.

C#
public class Author
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class BlogPost
{
    public string Title { get; set; }
    public Author { get; set; }
}

Assume that you want to find blog posts that have authors. Without a custom extension method, you cannot do that directly because there is no Exists method for the Author type. However, you know that authors always have an Id (which is obviously true in this case because the Id is a value type and is 0 if not specified), so the following code can accomplish this.

C#
client.Search<BlogPost>()
    .Filter(x => x.Author.Id.Exists());

You can make queries like this more convenient by adding a custom extension method.

C#
public static class AuthorFilters
{
    public static FilterExpression<Author> Exists(this Author author)
    {
        return new FilterExpression<Author>(
            x => x.Id.Exists());
    }
}

Next, rewrite the original query to check for the existance of an author instead of the existance of the author ID:

C#
client.Search<BlogPost>()
    .Filter(x => x.Author.Exists());

Alternatively, add a custom method for the BlogPost class:

C#
public static class BlogPostFilters
{
    public static FilterExpression<BlogPost> HasAuthor(this BlogPost blogPost)
    {
        return new FilterExpression<BlogPost>(
            x => x.Author.Id.Exists());
    }
}

Then you query can be:

C#
client.Search<BlogPost>()
    .Filter(x => x.HasAuthor());

Extending the filtering functionality by creating extension methods that return FilterExpression is not limited to checking for existance, or to single filters. Assuming that a user is logged in and a publication date exists on the BlogPost class, you can create a custom method for finding blog posts that are visible to the user:

C#
public static class BlogPostFilters
{
    public static FilterExpression<BlogPost> VisibleToUser(this BlogPost blogPost, User user)
    {
        return new FilterExpression<BlogPost>(x => 
            x.PublicationDate.InRange(DateTime.Now, DateTime.MaxValue) 
          | x.Author.Id.Match(user.Id));
    }
}

Returning a DelegateFilterBuilder

Extension methods returning an instance of DelegateFilterBuilder is one level closer because the DelegateFilterBuilder constructor requires an expression that returns an actual filter. This means that they are not as useful for extending the filtering functionality for complex types. Instead they are useful for extending the filtering functionality in ways that use filters that are not already exposed by the fluent API.

Comments