Entity Framework Core поддерживает ряд агрегатных операций, например, нахождение суммы по столбцу, количества элементов в выборке и т.д. Эти операции представлены такими методами как All, Any, Count, Sum, Min, Max, Average. Для рассмотрения агрегатных операций возьмем модели из прошлой темы:
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"); } }
Метод Any() позволяет проверить, есть ли в базе данных элемент с определенными признаками, и если есть, то метод возвратит значение true. Например, проверим, есть ли в базе данных пользователи, которые работают в компании Google:
bool result = db.Users.Any(u=>u.Company!.Name=="Google");
При выполнении это выражение преобразуется в следующий SQL-запрос:
SELECT EXISTS ( SELECT 1 FROM "Users" AS "u" INNER JOIN "Companies" AS "c" ON "u"."CompanyId" = "c"."Id" WHERE "c"."Name" = 'Google')
Метод All() позволяет проверит, удовлетворяют ли все элементы в базе данных определенному критерию. Например, проверим, все ли пользователи работают в компании Microsoft:
bool result = db.Users.All(u=>u.Company!.Name=="Microsoft");
При вызове будет выполняться следующий SQL-запрос:
SELECT NOT EXISTS ( SELECT 1 FROM "Users" AS "u" INNER JOIN "Companies" AS "c" ON "u"."CompanyId" = "c"."Id" WHERE ("c"."Name" <> 'Microsoft') OR "c"."Name" IS NULL)
Метод Count()
позволяет найти количество элементов в выборке:
using(ApplicationContext db = new ApplicationContext()) { int number1 = db.Users.Count(); // найдем кол-во пользователей, которые в имени содержат подстроку Tom int number2 = db.Users.Count(u => u.Name!.Contains("Tom")); Console.WriteLine(number1); Console.WriteLine(number2); }
В результате будут выполняться варажения SQL наподобие:
SELECT COUNT(*) FROM "Users" AS "u" SELECT COUNT(*) FROM Users AS u WHERE ('Tom' == '') || (instr(u.Name, 'Tom') > 0))
Для нахождения минимального, максимального и среднего значений по выборке применяются функции Min(), Max() и Average() соответственно. Найдем минимальный, максимальный и средний возраст пользователей:
using(ApplicationContext db = new ApplicationContext()) { // минимальный возраст int minAge = db.Users.Min(u=>u.Age); // максимальный возраст int maxAge = db.Users.Max(u=>u.Age); // средний возраст пользователей, которые работают в Microsoft double avgAge = db.Users.Where(u=>u.Company!.Name=="Microsoft") .Average(p => p.Age); Console.WriteLine(minAge); Console.WriteLine(maxAge); Console.WriteLine(avgAge); }
Эти запросы трансформируются в SQLite в следующие SQL-выражения:
SELECT MIN("u"."Age") FROM "Users" AS "u" SELECT MAX("u"."Age") FROM "Users" AS "u" SELECT AVG(CAST("u"."Age" AS REAL)) FROM "Users" AS "u" INNER JOIN "Companies" AS "c" ON "u"."CompanyId" = "c"."Id" WHERE "c"."Name" = 'Microsoft'
Для получения суммы значений используется метод Sum():
using(ApplicationContext db = new ApplicationContext()) { // суммарный возраст всех пользователей int sum1 = db.Users.Sum(u => u.Age); // суммарный возраст тех, кто работает в Microsoft int sum2 = db.Users.Where(u=>u.Company!.Name == "Microsoft") .Sum(u => u.Age); Console.WriteLine(sum1); Console.WriteLine(sum2); }
Во втором случае будет выполняться следующее SQL-выражение:
SELECT COALESCE(SUM("u"."Age"), 0) FROM "Users" AS "u" INNER JOIN "Companies" AS "c" ON "u"."CompanyId" = "c"."Id" WHERE "c"."Name" = 'Microsoft'