Проекция позволяет получить из набора объектов одного типа набор объектов другого типа.
Пусть у нас есть те же классы, что и в прошлой теме:
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);