Получение сгруппированных сумм из связанных таблиц в столбцы запросов linq - PullRequest
0 голосов
/ 30 октября 2018

Я хотел бы запросить таблицу (учетные записи), а также как часть запроса получить итоговые данные (итого) из другой таблицы (учетные записи). Как я могу переписать этот sql-запрос как linq-запрос? Это так же просто, как добавить группу по утверждению ... но группа по использованию сбивает меня с толку.

select 
(select sum(ap.Quantity * ap.LastPrice) from AccountPositions ap 
  where ap.AccountId = a.Accountid and ap.IsOpen = 0) as Total,
a.AccountId, a.Username, a.FirstName, a.LastName, a.AccountNumber
from Accounts a
where a.IsTrading = 1

Что-то вроде ???

var query = (from a in _context.Accounts
            join ap in _context.AccountPositions on ap.AccountId = a.AccountId
            where a.IsTrading == true && and ap.IsOpen == true
            select new {
                Total = ap.Sum(r => r.Quantity * r.LastPrice),
                AccountId = a.AccountId,
                Username = a.Username,
                FirstName = a.FirstName,
                LastName = a.LastName,
                AccountNumber = a.AccountNumber
                }); 

Желаемый результат:

Total   AccountId   Username    FirstName   LastName    AccountNumber
2500    496         brice       Brian       Rice        U399445
160     508         jdoe        John        Doe         U555322                                                             

Таблица:

Accounts
AccountId   Username    FirstName   LastName    AccountNumber   IsTrading
496         brice       Brian       Rice        U399445         1
498         bmarley     Bob         Marley      U443992         0
508         jdoe        John        Doe         U555332         1

AccountPositions
AccountPositionId   AccountId   Quantity    LastPrice   IsOpen
23                  496         10          200         1
24                  496         15          48          0
25                  508         8           20          1
26                  498         18          35          1
27                  496         5           100         1

1 Ответ

0 голосов
/ 03 ноября 2018

Как мне переписать этот sql-запрос как запрос linq? Это так же просто, как добавить группу по заявлению ...

Это даже проще, потому что рассматриваемый SQL-запрос использует один агрегат, возвращающий коррелированный подзапрос в предложении select, поэтому перевод в LINQ буквально один в один - просто используйте соответствующие операторы C # и помните, что в LINQ select идет последним И агрегатные методы, такие как Sum, находятся за пределами синтаксиса запроса LINQ :

var query =
    from a in _context.Accounts
    where a.IsTrading
    select new
    {
        Total = (from ap in _context.AccountPositions
                 where ap.AccountId == a.AccountId && ap.IsOpen
                 select ap.Quantity * ap.LastPrice).Sum(),
        a.AccountId,
        a.Username,
        a.FirstName,
        a.LastName,
        a.AccountNumber
    };

Но LINQ позволяет вам смешивать синтаксис запроса с синтаксисом метода , так что часть Sum может быть написана более естественно с использованием следующих слов:

Total = _context.AccountPositions
    .Where(ap => ap.AccountId == a.AccountId && ap.IsOpen)
    .Sum(ap => ap.Quantity * ap.LastPrice),

Наконец, если вы используете Entity Framework, отношения между Account и AccountPosition будут выражаться чем-то вроде

public ICollection<AccountPosition> AccountPositions { get; set; }

свойство навигации внутри Account класс. Что позволяет забыть об условиях объединения (корреляции), таких как ap.AccountId == a.AccountId - они будут применены автоматически и сконцентрированы только на логике вашего запроса (см. Не используйте Linq's Join. Navigate! ), например

Total = a.AccountPositions.Where(ap => ap.IsOpen).Sum(ap => ap.Quantity * ap.LastPrice),

Внутри запроса LINQ свойство навигации коллекции EF представляет собой так называемое групповое объединение - уникальную функцию LINQ (по крайней мере, не имеет прямого эквивалента в SQL). В LINQ синтаксис запроса выражается в виде join + into предложений. Допустим, вам нужно более одного агрегата. Групповое объединение поможет вам добиться этого без повторения корреляционной части.

Итак, в вашей модели запрос с использованием группового объединения будет выглядеть так:

from a in _context.Accounts
join ap in _context.AccountPositions on a.AccountId equals ap.AccountId into accountPositions

Отсюда у вас есть 2 переменные - a, представляющие Account и accountPositions, представляющие набор AccountPosition, связанных с этим Account.

Но вас интересуют только открытые позиции. Чтобы избежать повторения этого условия, вы можете использовать другой синтаксис запроса LINQ - предложение let . Таким образом, запрос продолжается с обоими фильтрами:

where a.IsTrading
let openPositions = accountPositions.Where(ap => ap.IsOpen)

Теперь у вас есть вся информация для получения окончательного результата, например:

select new
{
    // Aggregates
    TotalPrice = openPositions.Sum(ap => ap.Quantity * ap.LastPrice),
    TotalQuantity = openPositions.Sum(ap => ap.Quantity),
    OpenPositions = openPositions.Count(),
    // ...
    // Account info
    a.AccountId,
    a.Username,
    a.FirstName,
    a.LastName,
    a.AccountNumber
};
...