Member-only story
Using LINQ Expressions to Centralize Logic
Queries could appear multiple times in our application. How to reuse the code?
When we talk about business logic, we mostly refer to the rules that determine how data should be created, stored and updated/deleted. We understand that we need to centralize logic for model states mutations and for validating commands and model integrity. We put these reusable codes in model classes, which establish “rich” models instead of “anemic” models.
Often times, we don’t pay much attention to the logic of querying data. Thus, we write a new query clause every time it is needed. An example query could be scanning a group of people to get a list of those who are eligible to drive a vehicle. The query could be complex, which might involve predicates of checking a person’s age, checking a person’s vision score, and so on. This query could appear multiple times in our application. How to reuse the code? Also, if a new policy comes, how to safely refactor the code to represent a new logic?
In order to centralize business logic, we want to do the same thing as we treat “rich” models. In other words, we want put reusable query expressions in model classes.
In this post, we will go through a simple and contrived example to see how can we write reusable queries using LINQ Expressions.
Think about an Entity class Author
. We want to get a list of authors that hold membership levels of Gold and up. Be careful here. “Gold and up” doesn’t necessarily equal “Gold + Platinum” because a new membership level may be introduced some day.
public class Author
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Membership Membership { get; set; }
}
public enum Membership
{
Bronze,
Silver,
Gold,
Platinum
}
A quick solution to fulfill the requirement is to write a query in a controller action method, as below.
return await _dbContext.Authors
.Where(x => x.Membership == Membership.Gold ||
x.Membership == Membership.Platinum)
.Select(x => new AuthorViewModel(x))
.ToListAsync();