Enhancing queries with expression trees

An expression tree is a mechanism that allows developers to create expressions that are necessary for the filters in the queries. In .NET, we have Func<T, TResult> to wrap a Where predicate and use it in multiple occurrences. We could use the same mechanism to create expression trees and leverage them in query objects.

The generic IQueryExpression interface has a provision to create an expression through Func, the following code creates contract for AsExpression().

    public interface IQueryExpression<T>
{
Expression<Func<T, bool>> AsExpression();
}

The concrete expression class implements IQueryExpression with concrete methods and their interface counterpart and wraps the Where predicate inside the AsExpression method, which returns a Func object. The following code provides a wildcard search on all fields from the Post entity using the expression approach:

    public class GetPaginatedPostByKeywordQueryExpression :
IQueryExpression<Post>
{
public string Keyword { get; set; }
public Expression<Func<Post, bool>> AsExpression()
{
return (x => x.Title.ToLower().Contains(Keyword.ToLower())
|| x.Blog.Title.ToLower().Contains(Keyword.ToLower())
|| x.Blog.Subtitle.ToLower().Contains(Keyword.ToLower())
|| x.Category.Name.ToLower().Contains(Keyword.ToLower())
|| x.Content.ToLower().Contains(Keyword.ToLower())
|| x.Summary.ToLower().Contains(Keyword.ToLower())
|| x.Author.Username.ToLower().Contains(Keyword.ToLower())
|| x.Url.ToLower().Contains(Keyword.ToLower()));
}
}

The expression tree is used in the query object, as shown. It is obvious that the expression object is constructed and used as a parameter to the Where condition in the LINQ query. The below GetPaginatedPostByKeywordQuery implementation consumes the expression required for wild card search:

    public class GetPaginatedPostByKeywordQuery : QueryBase, 
IGetPaginatedPostByKeywordQuery<GetPaginatedPostByKeywordQuery>
{
// Code removed for brevity
public IEnumerable<Post> Handle()
{
var expression = new GetPaginatedPostByKeywordQueryExpression
{
Keyword = Keyword
};
return IncludeData
? Context.Posts.Include(p => p.Author).Include(p =>
p.Blog).Include(p => p.Category)
.AsQueryable()
.Where(expression.AsExpression())
.Skip(PageNumber - 1).Take(PageCount)
.ToList()
: Context.Posts
.AsQueryable()
.Where(expression.AsExpression())
.Skip(PageNumber - 1).Take(PageCount)
.ToList();
}
public async Task<IEnumerable<Post>> HandleAsync()
{
var expression = new GetPaginatedPostByKeywordQueryExpression
{
Keyword = Keyword
};
return IncludeData
? await Context.Posts.Include(p => p.Author).Include(p
=> p.Blog).Include(p => p.Category)
.AsQueryable()
.Where(expression.AsExpression())
.Skip(PageNumber - 1).Take(PageCount)
.ToListAsync()
: await Context.Posts
.AsQueryable()
.Where(expression.AsExpression())
.Skip(PageNumber - 1).Take(PageCount)
.ToListAsync();
}
}

Here, the controller code remains intact as it has nothing to do with expression tree implementation, as it's the responsibility of the query object and the controller usage is not affected due to this change.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset