Cортировка и проекция из базы данных

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

Проекция

Проекция позволяет получить из набора объектов одного типа набор объектов другого типа.

Пусть у нас есть те же классы, что и в прошлой теме:

using Microsoft.EntityFrameworkCore;
public class Company
{
    public int Id { get; set; }
    public string? Name { get; set; }
    public List<User> Users { get; set; } = new();
}

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 ApplicationContext : DbContext
{
    public DbSet<User> Users { get; set; } = null!; 
    public DbSet<Company> Companies { get; set; } = null!;

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlite("Data Source=helloapp.db");
    }
}

Допустим, нам надо добавить в результат выборки название компании. Мы можем использовать метод Include для подсоединения к объекту связанных данных из другой таблицы: var users = db.Users.Include(p=>p.Company). Но не всегда нужны все свойства выбираемых объектов. В этом случае мы можем применить метод Select для проекции извлеченных данных на новый тип:

using(ApplicationContext db = new ApplicationContext())
{
    var users = db.Users.Select(p => new 
	{ 
		Name = p.Name, 
		Age = p.Age, 
		Company = p.Company!.Name 
	});
    foreach (var user in users)
        Console.WriteLine($"{user.Name} ({user.Age}) - {user.Company}");
}

В итоге метод Select из полученных данных спроецирует новый тип. При выполнении этот запрос будет трансформироваться в следующее выражение SQL:

SELECT "u"."Name", "u"."Age", "c"."Name" AS "Company"
FROM "Users" AS "u"
INNER JOIN "Companies" AS "c" ON "u"."CompanyId" = "c"."Id"

В даном случае мы получим данные анонимного типа, но это также может быть определенный пользователем тип. Например:

public class UserModel
{
    public string? Name { get; set; }
    public string? Company { get; set; }
    public int Age { get; set; }
}

И спроецируем выборку на этот тип:

var users = db.Users.Select(p => new UserModel
{ 
	Name = p.Name, 
	Age = p.Age, 
	Company = p.Company!.Name 
});
foreach (UserModel user in users)
    Console.WriteLine($"{user.Name} ({user.Age}) - {user.Company}");

Сортировка

Чтобы отсортировать полученные из бд данных по определенному критерию по возрастанию применяется метод OrderBy, либо оператор orderby. Например, отсортируем объекты по возрастанию по свойству Name:

using(ApplicationContext db = new ApplicationContext())
{
    var users = db.Users.OrderBy(p=>p.Name);
    foreach (var user in users)
        Console.WriteLine($"{user.Id}.{user.Name} ({user.Age})");
}

В результате Entity Framework будет генерировать следующее выражение SQL, которое будет упорядочивать данные:

SELECT "u"."Id", "u"."Age", "u"."CompanyId", "u"."Name"
FROM "Users" AS "u"
ORDER BY "u"."Name"

В качестве альтернативы методу OrderBy можно использовать оператор orderby:

var users = from u in db.Users
            orderby u.Name
            select u;
foreach (User user in users)
    Console.WriteLine($"{user.Id}.{user.Name} ({user.Age})");

Для сортировки по убыванию применяется метод OrderByDescending():

var users = db.Users.OrderByDescending(u=>u.Name);

В этом случае к выражению SQL будет добавляться оператор DESC:

SELECT "u"."Id", "u"."Age", "u"."CompanyId", "u"."Name"
FROM "Users" AS "u"
ORDER BY "u"."Name" DESC

При необходимости упорядочить данные сразу по нескольким критериям можно использовать методы ThenBy()(для сортировки по возрастанию) и ThenByDescending(). Например, отсортируем по двум значениям:

var users = db.Users.OrderBy(u => u.Age).ThenBy(u=>u.Company!.Name);
Помощь сайту
Юмани:
410011174743222
Перевод на карту
Номер карты:
4048415020898850