Как мне переписать этот 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
};