Рассмотрим, как добавить в приложение сортировку данных. Для работы возьмем новый проект ASP.NET Core по типу ASP.NET Core Empty. Назовем его, к примеру, MvcApp.
Далее добавим в проект в папку Models следующие классы User и Company:
public class User { public int Id { get; set; } public string? Name { get; set; } public int Age { get; set; } public int? CompanyId { get; set; } public Company? Company { get; set; } } public class Company { public int Id { get; set; } public string? Name { get; set; } public List<User> Users { get; set; } = new(); }
Для взаимодействия с MS SQL Server через Entity Framework добавим в проект через Nuget пакет Microsoft.EntityFrameworkCore.SqlServer. Далее добавим в папку Models новый класс UsersContext, через который будем взаимодействовать с бд:
using Microsoft.EntityFrameworkCore; namespace MvcApp.Models { public class UsersContext : DbContext { public DbSet<User> Users { get; set; } = null!; public DbSet<Company> Companies { get; set; } = null!; public UsersContext(DbContextOptions<UsersContext> options) : base(options) { Database.EnsureCreated(); } } }
В файле Program.cs установим контекст данных и подключение к базе данных:
using Microsoft.EntityFrameworkCore; using MvcApp.Models; var builder = WebApplication.CreateBuilder(args); string connection = "Server = (localdb)\\mssqllocaldb;Database = userstoredb;Trusted_Connection=true"; builder.Services.AddDbContext<UsersContext>(options => options.UseSqlServer(connection)); builder.Services.AddControllersWithViews(); var app = builder.Build(); app.MapDefaultControllerRoute(); app.Run();
Итак, в классе User есть три свойства (не считая Id), по которым можно вести сортировку: Name, Age, Company. Сортировка может быть по возрастанию и по убыванию. Таким образом, мы получаем шесть критериев сортировки: сортировка по свойству Name по возрастанию, сортировка по свойству Name по убыванию и так далее. Для описания всех этих критериев добавим в папку Models перечисление SortState:
public enum SortState { NameAsc, // по имени по возрастанию NameDesc, // по имени по убыванию AgeAsc, // по возрасту по возрастанию AgeDesc, // по возрасту по убыванию CompanyAsc, // по компании по возрастанию CompanyDesc // по компании по убыванию }
Это перечисление хранит критерии сортировки в виде числовых констант.
Теперь определим в проекте в папке Controllers контроллера HomeController со следующим кодом:
using Microsoft.AspNetCore.Mvc; using Microsoft.EntityFrameworkCore; using MvcApp.Models; namespace MvcApp.Controllers { public class HomeController : Controller { UsersContext db; public HomeController(UsersContext context) { db = context; // добавим начальные данные для тестирования if (!db.Companies.Any()) { Company oracle = new Company { Name = "Oracle" }; Company google = new Company { Name = "Google" }; Company microsoft = new Company { Name = "Microsoft" }; Company apple = new Company { Name = "Apple" }; User user1 = new User { Name = "Олег Васильев", Company = oracle, Age = 26 }; User user2 = new User { Name = "Александр Овсов", Company = oracle, Age = 24 }; User user3 = new User { Name = "Алексей Петров", Company = microsoft, Age = 25 }; User user4 = new User { Name = "Иван Иванов", Company = microsoft, Age = 26 }; User user5 = new User { Name = "Петр Андреев", Company = microsoft, Age = 23 }; User user6 = new User { Name = "Василий Иванов", Company = google, Age = 23 }; User user7 = new User { Name = "Олег Кузнецов", Company = google, Age = 25 }; User user8 = new User { Name = "Андрей Петров", Company = apple, Age = 24 }; db.Companies.AddRange(oracle, microsoft, google, apple); db.Users.AddRange(user1, user2, user3, user4, user5, user6, user7, user8); db.SaveChanges(); } } public async Task<IActionResult> Index(SortState sortOrder = SortState.NameAsc) { IQueryable<User>? users = db.Users.Include(x => x.Company); ViewData["NameSort"] = sortOrder == SortState.NameAsc ? SortState.NameDesc : SortState.NameAsc; ViewData["AgeSort"] = sortOrder == SortState.AgeAsc ? SortState.AgeDesc : SortState.AgeAsc; ViewData["CompSort"] = sortOrder == SortState.CompanyAsc ? SortState.CompanyDesc : SortState.CompanyAsc; users = sortOrder switch { SortState.NameDesc => users.OrderByDescending(s => s.Name), SortState.AgeAsc => users.OrderBy(s => s.Age), SortState.AgeDesc => users.OrderByDescending(s => s.Age), SortState.CompanyAsc => users.OrderBy(s => s.Company!.Name), SortState.CompanyDesc => users.OrderByDescending(s => s.Company!.Name), _ => users.OrderBy(s => s.Name), }; return View(await users.AsNoTracking().ToListAsync()); } } }
Критерий сортировки передается в метод Index в виде параметра sortOrder. Мы ожидаем, что он будет равен одной из констант перечисления SortState. Если никакое значение не передается,
по по умолчанию считаем, что используется сортировка по имени по возрастанию: SortState sortOrder = SortState.NameAsc
Далее устанавливаем ряд переменных во ViewData, которые будут хранить значения для трех столбцов. Например, для свойства Name определено значение
ViewData["NameSort"]
. Если параметр sortOrder равен константе SortState.NameAsc
, то ViewData["NameSort"] присваивается
значение SortState.NameDesc
. То есть если ранее значение ViewData["NameSort"] указывало на сортировку по имени по возрастанию, то теперь
после сортировки оно будет указывать на сортировку по имени по убыванию. И наоборот.
Далее в методе в конструкции switch..case смотрит на значение sortOrder и производим сортировку с помощью метода OrderBy/OrderByDescending
.
В конце передаем полученные данные в представление.
И определим код в представлении Index.cshtml:
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @using MvcApp.Models @model IEnumerable<User> <h1>Список пользователей</h1> <table> <tr> <th> <a asp-action="Index" asp-route-sortOrder="@ViewBag.NameSort"> Имя </a> </th> <th> <a asp-action="Index" asp-route-sortOrder="@ViewBag.AgeSort"> Возраст </a> </th> <th> <a asp-action="Index" asp-route-sortOrder="@ViewBag.CompSort"> Компания </a> </th> </tr> @foreach (User u in Model) { <tr><td>@u.Name</td><td>@u.Age</td><td>@u.Company?.Name</td></tr> } </table>
В представлении каждый заголовок столбца будет представлять ссылку. То есть мы нажимаем на столбец, и отправляется запрос на сервер, который выполняет фильтрацию.
Каждая ссылка определена с помощью tag-хелпера:
<a asp-action="Index" asp-route-sortOrder="@ViewBag.NameSort">Имя</a>
Атрибут asp-route-sortOrder
позволяет задать параметр sortOrder, который будет передавать на сервер выбранный критерий сортировки. И в результате
будет создавать ссылка типа следующей:
http://localhost:xxxxx/?sortOrder=NameAsc
В итоге весь проект будет выглядеть так:
После запуска проекта с помощью нажатия на заголовки столбцов в таблице мы сможем отсортировать объекты по нужному столбцу: