Сортировка данных

Последнее обновление: 11.04.2022

Рассмотрим, как добавить в приложение сортировку данных. Для работы возьмем новый проект 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

В итоге весь проект будет выглядеть так:

Проект ASP.NET Core MVC на C# для сортировки объектов в Entity Framework

После запуска проекта с помощью нажатия на заголовки столбцов в таблице мы сможем отсортировать объекты по нужному столбцу:

Сортировка в ASP.NET Core MVC на C# в Entity Framework
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850