Reputation: 4239
I have an ASP .Net Core 2.1 Web Api. I was wondering if there is an "elegant solution" for constructing filters on my DbContext based on query strings? So... say I have one [optional] query string:
// GET: api/Accounts
[HttpGet]
public IEnumerable<File> GetAccount([FromQuery] bool? isActive)
{
if (isActive.HasValue)
return _context.Accounts.Where(a => a.IsActive == isActive.Value);
else
return _context.Accounts;
}
Simple enough... But say I have a number of (optional) query strings:
// GET: api/Accounts
[HttpGet]
public IEnumerable<File> GetAccount([FromQuery] bool? isActive, [FromQuery] string type, [FromQuery] int? agentId, [FromQuery] bool? someOtherFilter)
{
}
As you can see, constructing the filters now gets harder, because there can be a combination of filters, depending which ones have been supplied. I could check if the first query string has a value, if it does, perform the filter and save the results into a temp variable. Then I could check the next query string, if that has a value, then perform that filter on the temp variable, and so on and so on. But that sounds like it's going to be slow... Any other suggestions? Thanks...
Upvotes: 0
Views: 414
Reputation: 7213
You can check all your optional values with if/else
:
[HttpGet]
public IEnumerable<File> GetAccount([FromQuery] bool? isActive, [FromQuery] string type, [FromQuery] int? agentId, [FromQuery] bool? someOtherFilter)
{
var accounts = context.Accounts;
if(isActive.HasValue)
accounts.Where(a => a.IsActive == isActive.Value);
if(!string.IsNullOrEmpty(type))
accounts.Where(a => a.Type == type);
if(agentId.HasValue)
accounts.Where(a => a.AgentId == agentId.Value);
. . .
if(someOtherFilter.HasValue)
accounts.Where(a => a.SomeOtherFilter == someOtherFilter.Value);
}
or in linq to sql you can check for null
inside your Where()
method:
public IEnumerable<File> GetAccount([FromQuery] bool? isActive, [FromQuery] string type, [FromQuery] int? agentId, [FromQuery] bool? someOtherFilter) =>
context.Accounts.Where(a =>
(!isActive.HasValue || a.IsActive == isActive.Value) &&
(string.IsNullOrEmpty(type) || a.Type == type) &&
(!agentId.HasValue || a.AgentId== agentId.Value) &&
. . .
(!someOtherFilter.HasValue || a.SomeOtherFilter== someOtherFilter.Value);
Upvotes: 2
Reputation: 3551
I would suggest to add an extension to hide all the dirty work and create something like this:
public class AccountQuery
{
public bool IsActive { get; set; }
public int? AgentId { get; set; }
...
}
public static class Extensions
{
public static IQueryable<Account> ApplyFilter(this IQueryable<Account> query, AccountQuery queryObj)
{
if (queryObj.IsActive)
query = query.Where(...);
if (queryObj.AgentId.HasValue)
query = query.Where(...);
// some other filters
return query;
}
}
[HttpGet]
public IEnumerable<File> GetAccount([FromQuery] AccountQuery queryObj)
{
var query = _context.Accounts.AsQueryable();
query = query.ApplyFilter(queryObj);
...
}
Upvotes: 2