In previous article, we have seen how to implement a specification pattern with generic repository pattern and how it helps.
I got a question from one of the reader asking how this pattern can be enhanced further to use logican AND and OR operators in filter conditions. So, in this article, we are going to enhance implementation from previous post and add few more methods.
If we don’t design specification classes cleverly, it may result in a lot of different classes. Some developers may prefer
Multiple Filter Conditions in Same Expression
Below is our original BaseSpecification class. It supports sorting, grouping and filtering of records. It has only one property for filter condition. But note that its type is Expression<Func<T, bool>>. It means you can still specify multiple conditions in the same expression.
This would be helpful if one logical query needs multiple filter conditions, then those can be specified using a single specification class itself. For example, let’s say we want to get list of all posts written between two specific dates. In this case we want logical AND of two conditions,
- Published date should be less than or equal to the end date
- AND published date should be greater than or equal to the start date
For this, a custom specification class can be created as shown below.
Design Considerations
Sometimes, an application needs to query the data for different values of a property. Imagine an E-Commerce website (like amazon), which has a lot of different filters for filtering the products. Generally such websites have a slider with two draggable points, to specify price range (minimum and maximum price) so that site can show only products falling in that price range.
So, for such scenarios, there are two options
- either use BaseSpecification class and its constructor which takes filter expression as input parameter.
- OR create new class PriceSpecification, which takes min and max price as parameter and then constructs expression and sets it to the property
Generally an E-Commerce site has many different types of filters. Some of them may be :
- Filter products by price range
- Filter products by brand name selected by user
- Filter products by reviews (show only products having at least 4 stars in review)
So in such cases, one (and probably naive) approach would be to build an expression based on what inputs were provided. But this would cause domain conditions to be duplicated at multiple places.
So, can a generic implementation be created to combine specifications ? Because if we create a composition logic, that would mean all domain specific conditions would stay in their respective specification classes, thus avoiding duplication of the code.
Composite Specifications
Let’s say, you already have specification classes created for individual filters mentioned above. And then application developer receives new requirements. As per new requirements, a combination of those existing filters needs to be applied to Then you might have two options:
- Either implement a new specification class for every combination of filters
- Or implement a new class CompositeSpecification, which is a generic implementation. This implementation would combine all existing specification classes using logical operators.
If we go with first approach, it would result in a lot of classes, one for each combination of filters. While second approach is a generic class which uses existing specifications to create new combinations.
In this section, let’s have a look at how to implement a composite specifications. For this demo, we are going to consider two logical operations:
- And
- Or
We are going to use existing BaseSpecifications<T> class from previous post – in fact, actually its minified version, without related data, without sorting, etc. We are going to add two methods as shown below.
Also, two new specifications, AndSpecification and OrSpecification to create logical AND and logical OR of the filter expressions.
Example Usage
Now, let’s have a look at how these specifications can be used. Let’s create three specifications for our blog application.
- PostByIdSpepcification– to load a post by given id
- PostsWithoutCommentsSpecification – to load posts which have no comments
- PostsCreatedInLastMonthSpecification – to load posts created only in last 30 days.
Note that these are hypothetical specifications. Real world blog management system might not need such filters. These specifications are just to demonstrate how these specifications can be used to form a composite specifications.
Code snippet given below shows code for these three specifications.
The next code snippet shows PostsBusiness which uses these specifications to load the data and method from BaseRepository using the specifications passed to it.
References
I have referred below posts to modify the specification class.
I hope you found this information helpful. Let me know your thoughts.