C# Design Patterns – Creating a Dynamic Filter Builder

cobject-oriented

Say that I have an abstract base class Shape and its derived classes Triangle, Square, etc.

Currently I have the following (simplified) structure to fetch a list of Shapes and filter them (mostly using Fluent):

public abstract class BaseSearch<T> where T : Shape
{
    protected readonly IRepository<T> repository;

    public IQueryable<T> Search(Filter filter)
    {
        var shapes = repository.GetAll();
        // applies the common filtering to shapes

        return CustomSearch(filter, shapes);
    }

    public abstract IQueryable<T> CustomSearch(Filter filter, IQueryable<T> shapes);  
}  

public class TriangleSearch : BaseSearch<Triangle>
{
    public IQueryable<Triangle> CustomSearch(Filter filter, IQueryable<Triangle> shapes)
    {
        var filteredTriangles = shapes;
        // applies filters specific to Triangles
        return filteredTriangles;
    }
}

The same goes for the rest of the derived class. They just need to implement the CustomSearch method.

The problem is that now different places require different filters, with different conditions, properties, etc. Augmenting the Filter class to handle those extra requirements would make it too cubersome.

To solve this problem, I though about having many filter classes, each of them would apply its simple filter algorithm to a list of Squares. Then, using composition I could nest them all and have the whole filter I need.

The problem with this approach is that some properties lie in different places on each entity. For example, to filter by height, I need to compare the MiddleHeight property from Triangle and the Height property from Square. Also, neither of those properties are present in the Square class.

I also thought about using the Predicate Builder approach, but I would fall into the same problem.

What could be used to implement a more general or dynamic filter that could be used to filter instances of classes derived from Shape and still return an IQueryable of shapes?

Edit: explaining further the filter class and how its used.

public class Filter {
    public string Color { get; set; }
}

public class AnotherFilter {
    public Filter MainFilter { get; set; }
    public long? Height { get; set; }
}

The main search uses the Filter class. It checks if the Color property is set and if so, applies a condition to the collection of shapes. This condition is not always a simple "where the color of the shape matches the color set in the filter"; sometimes the property requires a more complex check (e.g. "where the color of the shape matches that of the filter and the shape has the opacity set to 0%").

The AnotherFilter class represents a different filter. Currently it has a Filter property which is used to call the main Search and fetch some results. Then, using the properties of AnotherFilter, the collection is filtered further. There is also a problem here mentioned before: the Height property is to be used to filter data by height. But Height is not a property of Shape, only of, say, Triangle and Square (a Circle, which also inherits from Shape, doesn't have a height).

The search fetches data from a remote database and uses NHibernate.

Best Answer

Use Dynamic Linq.

enter image description here

Dynamic linq will allow you to write "stringly-typed" queries with conditional statements that can be created and resolved at run time, rather than at compile time.

Further Reading
Getting Started with Dynamic Linq