Какие есть типы запросов в LINQ?

Ответ

В LINQ (Language Integrated Query) можно выделить типы по синтаксису написания и по источнику данных.

1. Типы по синтаксису

a) Синтаксис запросов (Query Syntax)

Напоминает SQL, использует ключевые слова from, where, select, group by, orderby и т.д.

// Пример: выборка и сортировка
var query = from product in products
            where product.Price > 100 && product.Category == "Electronics"
            orderby product.Price descending
            select new { product.Name, product.Price };

Плюсы: Читаемость для сложных операций соединения (join) и группировки. Минусы: Поддерживает не все операторы LINQ.

b) Синтаксис методов (Method Syntax / Fluent Syntax)

Использует цепочки методов расширения (Where, Select, OrderBy), основанные на лямбда-выражениях.

// Тот же запрос в синтаксисе методов
var query = products
    .Where(p => p.Price > 100 && p.Category == "Electronics")
    .OrderByDescending(p => p.Price)
    .Select(p => new { p.Name, p.Price });

Плюсы: Более гибкий, поддерживает все операторы LINQ, компактный для простых запросов. Минусы: Цепочки могут стать длинными и менее читаемыми.

Важно: Оба синтаксиса компилируются в одинаковый IL-код. Их можно комбинировать в одном запросе.

2. Типы по источнику данных (технологии LINQ)

a) LINQ to Objects

Работает с любыми коллекциями в памяти, реализующими IEnumerable<T>.

List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
var evenNumbers = numbers.Where(n => n % 2 == 0).ToList();

b) LINQ to Entities (ранее LINQ to SQL)

Используется с Entity Framework Core. Запросы транслируются в SQL и выполняются на стороне базы данных.

// DbContext - часть Entity Framework Core
using var db = new AppDbContext();
var users = await db.Users
                    .Where(u => u.IsActive)
                    .OrderBy(u => u.LastName)
                    .ToListAsync(); // Генерирует и выполняет SQL

c) LINQ to XML

Предоставляет удобный API для работы с XML-документами.

XDocument doc = XDocument.Load("data.xml");
var titles = from element in doc.Descendants("book")
             where (int)element.Element("price") > 20
             select element.Element("title").Value;

d) Parallel LINQ (PLINQ)

Расширение LINQ to Objects для параллельного выполнения запросов на многоядерных процессорах.

var source = Enumerable.Range(1, 1000000);
var parallelQuery = source.AsParallel()
                         .Where(n => n % 2 == 0)
                         .ToArray(); // Выполняется параллельно

Ключевой принцип: Независимо от типа, LINQ использует отложенное выполнение (deferred execution). Запрос не выполняется до момента реальной итерации по результатам (например, в foreach, ToList(), Count()). Это позволяет строить и комбинировать запросы эффективно.

Ответ 18+ 🔞

А, LINQ, говоришь? Ну это ж, блядь, наше всё, как водка и балалайка в мире C#. Смотри, тут всё просто, но если не вникать — можно мозг сломать, как сухарик в борще.

Вот смотри, есть два главных способа эту штуку писать. Прям как водку пить — можно аккуратно из рюмки, а можно, прости господи, из горла.

Первый способ — для интеллигентов, которые SQL знают. Выглядит, будто с базой данных разговариваешь.

// Типа, выбери мне из всех продуктов дорогие электронные штуки и отсортируй по цене, чтоб самые жирные сверху были
var дорогиеШтуки = from штука in всеШтуки
                   where штука.Цена > 100 && штука.Категория == "Электроника"
                   orderby штука.Цена descending
                   select new { штука.Название, штука.Цена };

Выглядит чисто, читается легко, особенно если нужно таблицы между собой соединить (join). Но, сука, не всё через это можно сделать, иногда функционала не хватает.

Второй способ — для настоящих пацанов, которые любят цепочки. Тут всё через точки и стрелочки.

// Тот же запрос, но в стиле "не мешай мне, я строю"
var дорогиеШтуки = всеШтуки
    .Where(ш => ш.Цена > 100 && ш.Категория == "Электроника")
    .OrderByDescending(ш => ш.Цена)
    .Select(ш => new { ш.Название, ш.Цена });

Этот способ, блядь, всеяден. Всё, что захочешь, можно сделать. Но если наворотить слишком длинную цепочку, можно самому в ней запутаться, как кот в клубке. А под капотом-то, ёпта, оба способа в одно и то же компилируются! Их даже мешать можно, но зачем усложнять?


А теперь, внимание, самое важное: куда этот LINQ применяется. Тут вариантов — как собак нерезаных.

  1. LINQ to Objects. Это когда ты колупаешься в своих списках и массивах прямо в памяти. Основа основ.

    List<int> циферки = new List<int> { 1, 2, 3, 4, 5 };
    var чётные = циферки.Where(n => n % 2 == 0).ToList(); // Отфильтровал и всё тут
  2. LINQ to Entities (раньше LINQ to SQL). Вот это, блядь, магия. Ты пишешь запрос на C#, а Entity Framework берёт и превращает его в SQL, летящий прямиком в базу данных. Выглядит так же, а работает иначе.

    using var db = new КонтекстБазы();
    var пользователи = await db.Пользователи
                                .Where(u => u.Активен)
                                .OrderBy(u => u.Фамилия)
                                .ToListAsync(); // Вжух — и SQL запрос готов!
  3. LINQ to XML. Для тех, кому приходится ковыряться в этих ваших XML-файлах. Делает процесс менее болезненным.

    var doc = XDocument.Load("данные.xml");
    var названия = from element in doc.Descendants("book")
                   where (int)element.Element("price") > 20
                   select element.Element("title").Value;
  4. Parallel LINQ (PLINQ). А это для тех, у кого процессор ядер дохуя и он хочет их все загрузить. Кинул .AsParallel() и поехали фильтровать миллион записей в несколько потоков.

    var source = Enumerable.Range(1, 1000000);
    var результат = source.AsParallel()
                         .Where(n => n % 2 == 0)
                         .ToArray(); // Работает быстрее, потому что параллельно!

И запомни, чувак, главный фокус всей этой кухни — отложенное выполнение. Это значит, что когда ты строил эту красивую цепочку из Where, Select и OrderBy, нихуя не происходило! Запрос выполнится только в тот момент, когда ты реально попросишь результат — в foreach, или через ToList(), или Count(). Это, с одной стороны, эффективно, а с другой — можно нечаянно десять раз к базе данных сходить, если невнимательный. Так что держи ухо востро.