Статьи

LINQ и Java

LINQ был довольно успешным, но и спорным дополнением к экосистеме .NET . Многие люди ищут сопоставимое решение в мире Java. Чтобы лучше понять, каким может быть сопоставимое решение, давайте взглянем на основную проблему, которую решает LINQ:

Языки запросов часто являются декларативными языками программирования со многими ключевыми словами. Они предлагают немного элементов потока управления, но они очень описательны. Самым популярным языком запросов является SQL , стандартизированный ISO / IEC язык структурированных запросов, в основном используемый для реляционных баз данных.

Декларативное программирование означает, что программисты явно не формулируют свои алгоритмы. Вместо этого они описывают результат, который хотели бы получить, оставляя алгоритмическое исчисление своим системам реализации. Некоторые базы данных стали очень хорошими в интерпретации больших операторов SQL, применяя правила преобразования языка SQL, основанные на синтаксисе языка и метаданных. Интересное прочтение имеет значение метаданных Тома Кайта , намекающих на невероятные усилия, которые были вложены в оптимизатор Oracle на основе затрат Аналогичные документы можно найти для SQL Server, DB2 и других ведущих СУБД.

LINQ-to-SQL не является SQL

LINQ — это совершенно другой язык запросов, который позволяет встраивать декларативные аспекты программирования в языки .NET, такие как C # или ASP. Приятной частью LINQ является тот факт, что компилятор C # может скомпилировать нечто похожее на SQL в середине операторов C #. В некотором смысле LINQ для .NET — это то, что SQL для PL / SQL, pgplsql или jOOQ для Java ( см. Мою предыдущую статью о PL / Java ). Но в отличие от PL / SQL, в который встроен настоящий язык SQL, LINQ-to-SQL не нацелен на моделирование самого SQL в .NET. Это высокоуровневая абстракция, которая оставляет открытой дверь для попыток унифицировать запросы к различным разнородным хранилищам данных на одном языке. Это объединение создаст такое же несоответствие импеданса, как и раньше, возможно, даже большее. Хотя аналогичные языки могут быть в определенной степени преобразованы друг в друга, для опытного разработчика SQL может быть довольно сложно предсказать, какой фактический код SQL будет сгенерирован даже из очень простых операторов LINQ.

LINQ Примеры

Это становится более понятным при рассмотрении некоторых примеров, приведенных в документации LINQ-to-SQL. Например, агрегатная функция Count() :

1
2
3
4
5
6
7
System.Int32 notDiscontinuedCount =
    (from prod in db.Products
    where !prod.Discontinued
    select prod)
    .Count();
 
Console.WriteLine(notDiscontinuedCount);

В приведенном выше примере неясно, будет ли .Count() преобразована в агрегатную функцию SQL count(*) в запросе в скобках (тогда почему бы не поместить ее в проекцию?) Или она будет применена только после выполнения запроса, в памяти приложения. Последнее было бы недопустимым, если бы большое количество или записи необходимо было перенести из базы данных в память. В зависимости от модели транзакции их даже нужно заблокировать на чтение!

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

1
2
3
4
5
6
7
8
9
var prodCountQuery =
    from prod in db.Products
    group prod by prod.CategoryID into grouping
    where grouping.Count() >= 10
    select new
    {
        grouping.Key,
        ProductCount = grouping.Count()
    };

В этом случае LINQ моделирует языковые аспекты, полностью отличающиеся от SQL. Вышеуказанное предложение LINQ where , очевидно, является предложением SQL HAVING . into grouping есть псевдоним для того, что будет сгруппированным кортежем, что довольно хорошая идея. Это, однако, напрямую не сопоставляется с SQL и должно использоваться LINQ для внутреннего использования для получения типизированного вывода. Что удивительно, конечно, статически типизированные проекции, которые впоследствии можно использовать повторно, прямо в C #!

Давайте посмотрим на другой пример группировки:

1
2
3
4
5
6
7
8
var priceQuery =
    from prod in db.Products
    group prod by prod.CategoryID into grouping
    select new
    {
        grouping.Key,
        TotalPrice = grouping.Sum(p => p.UnitPrice)
    };

В этом примере функциональные аспекты C # встроены в агрегатное выражение LINQ Sum(p => p.UnitPrice) . TotalPrice = ... это просто псевдонимы столбцов. Вышеизложенное оставляет мне много открытых вопросов. Как я могу контролировать, какие части действительно будут переведены в SQL, и какие части будут выполняться в моем приложении после того, как SQL-запрос вернет частичный набор результатов? Как я могу предсказать, подходит ли лямбда-выражение для агрегатной функции LINQ, и когда это приведет к загрузке огромного объема данных в память для агрегирования в памяти? А также: предупредит ли меня компилятор, что он не может понять, как создать смесь алгоритмов C # / SQL? Или это просто потерпит неудачу во время выполнения?

LINQ или нет LINQ

Не пойми меня неправильно. Всякий раз, когда я заглядываю в руководства LINQ для вдохновения, у меня возникает сильное желание попробовать это в проекте. Это выглядит потрясающе и хорошо продумано. Есть также много интересных вопросов LINQ по переполнению стека . Я не возражаю против использования LINQ в Java , но я хочу напомнить читателям, что LINQ — это НЕ SQL. Если вы хотите контролировать свои API SQL, LINQ или LINQesque, это может быть плохим выбором по двум причинам:

  1. Некоторые механизмы SQL не могут быть выражены в LINQ. Как и в случае с JPA, вам может понадобиться простой SQL.
  2. Некоторые механизмы LINQ не могут быть выражены в SQL. Как и в случае с JPA, вы можете страдать от серьезных проблем с производительностью и, таким образом, снова прибегнуть к простому SQL.

Остерегайтесь вышесказанного при выборе LINQ или его «реализации Java»! Возможно, вам лучше использовать SQL (т.е. JDBC, jOOQ или MyBatis ) для выборки данных и API Java (например, Stream API Java 8) для пост-обработки в памяти

LINQ-подобные библиотеки, моделирующие SQL в Java, Scala

LINQ-подобные библиотеки, абстрагирующие синтаксис SQL и хранилища данных в Java, Scala

Ссылка: LINQ и Java от нашего партнера по JCG Лукаса Эдера из блога JAVA, SQL и JOOQ .