Агрегатные операции

  • Михаил
  • 12 мин. на прочтение
  • 112
  • 15 Nov 2022
  • 15 Nov 2022

Entity Framework Core поддерживает обращение к встроенным функциями SQL через специальные методы Count, Sum и т.д. Для примера возьмем модели из прошлой темы:

public class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
    public List<User> Users { get; set; } = new List<User>();
}
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<Company> Companies { get; set; }
    public DbSet<User> Users { get; set; }
         
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=helloappdb;Trusted_Connection=True;");
    }
}

Наличие элементов

Метод Any() позволяет проверить, есть ли в базе данных элемент с определенными признаками, и если есть, то метод возвратит значение true. Например, проверим, есть ли в базе данных пользователи, которые работают в компании Google:

bool result = db.Users.Any(u=>u.Company.Name=="Google");

При выполнении это выражение преобразуется в следующий SQL-запрос:

SELECT CASE
    WHEN EXISTS (
        SELECT 1
        FROM [Users] AS [u]
        INNER JOIN [Companies] AS [c] ON [u].[CompanyId] = [c].[Id]
        WHERE ([c].[Name] = N'Google') THEN CAST(1 AS BIT)
    ELSE CAST(0 AS BIT)
END

Метод All() позволяет проверит, удовлетворяют ли все элементы в базе данных определенному критерию. Например, проверим, все ли пользователи работают в компании Microsoft:

bool result = db.Users.All(u=>u.Company.Name=="Microsoft");

При вызове будет выполняться следующий SQL-запрос:

SELECT CASE
    WHEN NOT EXISTS (
        SELECT 1
        FROM [Users] AS [u]
        INNER JOIN [Companies] AS [c] ON [u].[CompanyId] = [c].[Id]
        WHERE ([c].[Name] <> N'Microsoft') OR [c].[Name] IS NULL)
    THEN CAST(1 AS BIT)
    ELSE CAST(0 AS BIT)
END

Количество элементов в выборке

Метод 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]
WHERE [u].[Name] LIKE  N'%Tom%'

Минимальное, максимальное и среднее значения

Для нахождения минимального, максимального и среднего значений по выборке применяются функции 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);
}

Эти запросы трансформируются в следующие SQL-выражения:

SELECT MIN([u].[Age])
FROM [Users] AS [u]
SELECT MAX([u].[Age])
FROM [Users] AS [u]
SELECT AVG(CAST([u].[Age] AS float))
FROM [Users] AS [u]
INNER JOIN [Companies] AS [c] ON [u].[CompanyId] = [c].[Id]
WHERE [c].[Name] = N'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] = N'Microsoft'