В то время как SQL и LINQ имеют некоторые общие черты, они сильно отличаются в своей работе. Лучше всего начать с того, как IEnumerable
работает с этим типом запроса, а затем с того, как он переводится на IQueryable
. В большинстве простых случаев они выглядят совершенно одинаково по своему дизайну.
Расширение Select
для IEnumerable
выполняет итерацию последовательности и передает каждый объект в предоставленную функцию, собирая результаты в новом IEnumerable
соответствующего типа. В вашем коде a
будет запись , а не коллекция.
По сути Select
выглядит так под капотом:
public static IEnumerable<TResult> Select<TElement, TResult>(this IEnumerable<TElement> seq, Func<TElement, TResult> selector)
{
foreach (var item in seq)
yield return selector(item);
}
Простыми словами Select
- это трансформация. Он берет объекты одного типа и передает их через функцию преобразования.
Расширение Max
- по крайней мере, соответствующее - обрабатывает последовательность объектов, использует предоставленную функцию для извлечения некоторого значения из каждого объекта, а затем возвращает наибольшее из этих значений. Это немного похоже на этот псевдокод:
public static TResult Max<TElement, TResult>(this IEnumerable<TElement> seq, Func<TElement, TResult> valueFunc)
{
var result = default(TResult);
foreach (var item in seq)
{
var curr = valueFunc(item);
if (result == default(TResult) || result < curr)
result = curr;
}
return curr;
}
Хорошо, что не скомпилируется, но показывает основную концепцию.
Итак, если у вас в памяти есть массив из Personel
объектов и вы хотите найти наибольшее значение code
, вы должны сделать это:
var maxCode = personel.Max(p => p.code);
Приятной особенностью LinqToSQL и почти всех LINQ-подобных ORM (Entity Framework, LinqToDB и т. Д.) Является то, что точно такая же вещь работает для IQueryable
:
var maxCode = dbContext.personel.Max(p => p.code);
Фактический SQL для этого будет выглядеть примерно так (фактический вывод из GenqToDB code gen):
SELECT
Max([t1].[code]) as [c1]
FROM
[personel] [t1]
Для более интересных запросов синтаксис отличается.
У вас есть две Amelia
записи разных возрастов. Допустим, вы хотите найти возрастной диапазон для каждого имени в вашем списке. Здесь начинается группировка.
В синтаксисе запроса LINQ запрос будет выглядеть примерно так:
var nameAges =
from p in dbContext.personel
group p.old by p.name into grp
select new { name = grp.Key, lowAge = grp.Min(), highAge = grp.Max() };
Группировать проще в этом формате. На беглом языке это выглядит как:
var nameAges = dbContext.personel
.GroupBy(p => p.name, p => p.old)
.Select(grp => new { name = grp.Key, lowAge = grp.Min(), highAge = grp.Max() };
Или в SQL:
SELECT name, Min(code) AS lowAge, Max(code) AS highAge
FROM personel
GROUP BY name
Мораль в том, что написание LINQ-запросов не такое же, как написание SQL-запросов ... но концепции похожи. Поиграйте с ними, выясните, как они работают. LINQ - отличный инструмент, если вы его понимаете.