I have an ASP.Net MVC3 web application that displays a list of parts (A part is a simple entity with a number and a description).
I have updated the action method to support filtering and paging:
[HttpGet]
public ViewResult Index(int page = 1, int pageSize = 30, string filter = "All")
{
IEnumerable<Part> parts;
int totalParts;
var acceptableFilters = new string[] {
"All", "123", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
"M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z" };
// This checks that the filter value received by the method is an acceptable value.
// E.G. If a user types in a value in the query string that is not contained in the
// array above, then the filter is reset to 'All' and all records are queried.
if (!acceptableFilters.Contains(filter))
{
filter = "All";
}
if (filter == "All")
{
parts = Database.Parts
.OrderBy(p => p.Number)
.Skip((page - 1) * pageSize)
.Take(pageSize);
totalParts = Database.Parts.Count();
}
else if (filter == "123")
{
var numbers = new string[]{"1","2","3","4","5","6","7","8","9","0"};
parts = Database.Parts
.OrderBy(p => p.Number)
.Where(p=> numbers.Contains(p.Number.Substring(0,1)))
.Skip((page - 1) * pageSize)
.Take(pageSize);
totalParts = Database.Parts
.Count(p => numbers.Contains(p.Number.Substring(0, 1)));
}
else
{
parts = Database.Parts
.OrderBy(p => p.Number)
.Where(p => p.Number.StartsWith(filter))
.Skip((page - 1) * pageSize)
.Take(pageSize);
totalParts = Database.Parts.Count(p => p.Number.StartsWith(filter));
}
PartsListViewModel viewModel = new PartsListViewModel()
{
Filter = filter,
PageInfo = new PageInfo(page, pageSize, totalParts),
Parts = parts,
};
return View(viewModel);
}
The idea is this:
- If the filter is equal to 'All' then query all records.
- If the filter is equal to '123' then query all records that start with a number.
- if the filter is equal to a letter (A, B, C) then query all records that begin with said letter.
Once the required records have been queried I then need to do some calculations to determine how many pages I have and how many items to display on each page.
This works perfectly but I do not like the code I currently have, specifically the if statement that determines the Linq query to be used as the majority of the code is identical except for the where clause (or lack of where clause if all records are being pulled down). I also don't like the fact that I have to run each query twice: once to get the records and a second time to determine the total record set size.
So, is there a better way of achieving the same result? can the Linq queries be restructured in a more elegant way to reduce the redundant code or is this the best way?