I've created a nuget package Linq.Extension.PredicateBuilder helps you to solve complexity in filter collection by apply filtering on combination of properties.
Overview
To make the scenario concrete, let's assume that our object is declared as follows:
public class Post
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public bool IsPublished { get; set; }
public DateTime PublishedAt { get; set; }
public int TotalViews { get; set; }
public int TotalComments { get; set; }
}
Now suppose we have a collection of Posts like this (this is just for explanation purposes, in real life you would get a much bigger collection from database
var posts = new List<Post>
{
new Post {Id = 1, Name = "post1" , Description = "post1 description", IsPublished = true, PublishedAt = DateTime.Now, TotalViews = 50, TotalComments = 4},
new Post {Id = 2, Name = "post2" , Description = "post2 description", IsPublished = false, PublishedAt = DateTime.Now.AddDays(-3), TotalViews = 10, TotalComments = 1},
new Post {Id = 3, Name = "post3" , Description = "post3 description", IsPublished = true, PublishedAt = DateTime.Now.AddDays(-8), TotalViews = 120, TotalComments = 8},
new Post {Id = 4, Name = "post4" , Description = "post4 description", IsPublished = true, PublishedAt = DateTime.Now.AddDays(-1), TotalViews = 40, TotalComments = 5},
new Post {Id = 5, Name = "post5" , Description = "post5 description", IsPublished = true, PublishedAt = DateTime.Now, TotalViews = 0, TotalComments = 0},
new Post {Id = 6, Name = "post6" , Description = "post6 description", IsPublished = true, PublishedAt = DateTime.Now.AddDays(-10), TotalViews = 150, TotalComments = 10},
new Post {Id = 7, Name = "post7" , Description = "post7 description", IsPublished = false, PublishedAt = DateTime.Now, TotalViews = 0, TotalComments = 0},
new Post {Id = 8, Name = "post8" , Description = "post8 description", IsPublished = true, PublishedAt = DateTime.Now.AddDays(-20), TotalViews = 250, TotalComments = 15},
};
Suppose we want to allow the user to filter the collection on any property or any combination of properties, one way would be to have a function for each property and each combination of properties, something like:
public IList<Post> FilterByName(string name)
{
return posts.Where(p => p.Name == name).ToList();
}
public IList<posts> FilterByDescription(string description)
{
return posts.Where(p => p.Description.Contains(description)).ToList();
}
public IList<posts> FilterByTotalViewsGreaterOrEqual(int totalViews)
{
return posts.Where(p => p.TotalViews >= totalViews).ToList();
}
As you can see, this becomes a very tedious job since the number of functions to cover all possible combinations is quite big.
The other way to filter the collection, which is much more convenient and tidier is to build an expression tree dynamically and pass it to the where clause for filtering so Linq.Extension.PredicateBuilder comes
Installation
dotnet add package Linq.Extension.PredicateBuilder
Usage
using Linq.Extension.PredicateBuilder;
namespace ConsoleAppTest
{
internal class Program
{
static void Main(string[] args)
{
var searchFilters = new List<SearchFilter> {
new SearchFilter{PropertyName = "Name", Operation = OperatorComparer.BeginsWith, Value = "post" },
new SearchFilter{PropertyName = "IsPublished", Operation = OperatorComparer.Equal, Value = true },
new SearchFilter{PropertyName = "TotalViews", Operation = OperatorComparer.GreaterOrEqual, Value = 150 },
};
var predicate = PredicateBuilder.Compile<Post>(searchFilters);
var filteredPostsResult = new Post().GetPosts().Where(predicate).ToList();
}
}
}
Top comments (0)