-
Notifications
You must be signed in to change notification settings - Fork 11
Sorting Feature
We have a Database with a List of Jokes. The jokes have owners and all are loosely coupled using DDD. First off we need to know what to sort with so we make a model with all possibilities. As this is a Data Transfer Object (Dto) we call it as such:
public class JokesFilterDto
{
public string AuthorId { get; set; }
public string Text { get; set; }
public int MinimumLikes { get; set; } = int.MinValue;
public int MaximumLikes { get; set; } = int.MaxValue;
public DateTime MinimumDate { get; set; } = DateTime.MinValue;
public DateTime MaximumDate { get; set; } = DateTime.MaxValue;
}
we set standard values for int and DateTime to differentiate between a user input and no input.
[AllowAnonymous]
[HttpGet("Results")]
public async Task<ActionResult<IEnumerable<JokeReplyDto>>> GetFilteredJokesAsync([FromQuery]JokesFilterDto jokesFilter)
{
var jokeDtos = await _jokesService.GetFilteredJokeDtosAsync(jokesFilter);
return Ok(jokeDtos);
}
The controller is setup with a new path Using DataAnnotations [HttpGet("Results")]
The path should now be api/jokes/results
we use the Dto to get the filters we want to filter by. so we add the Dto model as a parameter: JokesFilterDto jokesFilter
but this alone is not enough as a get action should not accept a body (it can! but is most of the time not recommended )
so we add the annotation [FromQuery]
this will read the URL and build the DtoModel from that.
https://localhost:5001/api/Jokes/Results = you get all jokes with no filter.
https://localhost:5001/api/Jokes/Results?Text=who = search all texts for "who"
https://localhost:5001/api/Jokes/Results?AuthorId=16c070d1-2e08-4889-b4cf-2567ebb20832&Text=who = search all texts for "who" With userId ...
https://localhost:5001/api/Jokes/Results?MinimumLikes=0&MaximumDate=01-01-2030 = search with minimum likes and maximum date.
Inside the Repository we create a new method where we can filter the jokes.
We start by creating a query (a line of text that will be sent to the database to call for what you need)
var query = _context.Jokes.AsQueryable();
We check each clause to see if there is user input. and if so we add onto the query with a .Where()
if (!string.IsNullOrWhiteSpace(jokesFilter.AuthorId))
{
query = query.Where(joke => joke.AuthorId == jokesFilter.AuthorId);
}
if (jokesFilter.MinimumLikes != int.MinValue || jokesFilter.MaximumLikes != int.MaxValue)
{
query = query.Where(joke => joke.Likes >= jokesFilter.MinimumLikes && joke.Likes <= jokesFilter.MaximumLikes);
}
if (jokesFilter.MinimumDate != DateTime.MinValue || jokesFilter.MaximumDate != DateTime.MaxValue)
{
query = query.Where(joke => joke.UploadDate >= jokesFilter.MinimumDate && joke.UploadDate <= jokesFilter.MaximumDate.AddDays(1));
}
if (!string.IsNullOrEmpty(jokesFilter.Text))
{
query = query.Where(joke => joke.NormalizedPremise.Contains(jokesFilter.Text.ToUpper()) ||
joke.NormalizedPunchLine.Contains(jokesFilter.Text.ToUpper()));
}
then we call .ProjectTo<JokeReplyDto>(_mapper.ConfigurationProvider)
to project the model onto the Dto reply object.
finally we call .ToListAsync()
this sends the full query command to the Database asynchronously.
then we can return whatever result comes out of that.
MS Tutorial: Add sorting, filtering, and paging SO How to pass multiple parameters to a get method in ASP.NET Core SO GET/HEAD method cannot have body Swagger not allowing Body on Get