Стоит ли использовать LINQ


24 0

Еще когда появился Linq, я назвал эту технологию прикольной, но не рекомендовал к использованию. И я сам не использовал его вплоть до ноября прошлого года. В ноябре на работе дали небольшой проект, в котором мы не могли использовать внутренние наработки, потому что весь исходный код мы должны были передать клиенту и сайт хостится на стороне клиента.

Перед началом работы над сайтом я спросил парня, с которым мы делали сайт, что он хочет использовать и он предложил Entity Framework в связке с Linq, потому что он уже имел опыт работы с этими технологиями. Ну и фиг с ним, я учусь мега быстро, поэтому согласился. Ну что я могу сказать. . . , Microsoft уже придумало дофига различных технологий и фреймворков доступа к данным и поверьте мне, Entity Framework – не последний, потому что ничего особенного там нет, только неудобства.

Я с громадным шоком узнал, что операция .OrderBy(string) возможна далеко не всегда. У нас есть правило, что если мы строим какую-то таблицу данных на странице, то таблица должна сортироваться по любой колонке, которую захочет пользователь. Во внутренне корпоративном фреймворке это решается банально:

TableName.FindSql("Sql").OrderBt("имя колонки");

Обрати внимание, что имя колонки передается в виде простой строки и фреймворк может без проблем подставить эту колонку к SQL запросу, а нам легко ее передавать. У Linq это работает далеко не всегда.

Когда мы закончили проект, я посмотрел на получившийся код и просто в голове проскочила мысль – ну и что с того, что мы использовали LINQ? Может быть код более читабельный? Нет, код выглядит абсолютно нечитабельно на мой взгляд и команды выборки данных занимают по три-четыре строчки кода, чтобы их можно было видеть полностью на экране.

Единственное, что мне понравилось в Linq, так это использование Top и Skip, потому что они выглядят более элегантно в коде, чем любые SQL аналоги создания страниц (блин, уже не знаю, как лучше по-русски сказать слово pagination) в таблицах. Но если бы Microsoft добавила в свой SQL оператор limit, который есть в MySQL, то их Transact-SQL тут же стал бы на много элегантнее, чем Top и Skip в LINQ.

Но допустим, что вам нравится синтаксис Linq и вам нравится строить эти уродливые конструкции .Where().Top().Skip().OrderBy().FirstOrDefault() и что там еще есть. Я все равно не рекомендую использовать LINQ, потому что выгоды от него меньше, чем недостатков. Код становится непереносимым на другие платформы и если вы захотите потом сграбить реальный SQL запрос и скопировать его в проект на Java, вы просто решите удалить проект и писать его заново.

Украсть SQL запрос из Linq возможно, просто запустите профайлер и стыбрите SQL запрос, который для вам генерирует Linq. Но использовать его потом будет нереально, потому что он будет выглядеть нечитаемо. Linq использует полные имена таблиц в качестве псевдонимов и результат получается на столько уродлив, что проще написать SQL c нуля.

Если вы пишете на SQL а не Linq, то вас будет понимать весь мир, вы легко можете общаться с теми, кто пишет на Java, вы легко можете портировать SQL код куда угодно. Linq отбирает все это и ничего не дает в замен.

Я уже много раз показывал на блоге случаи, когда оптимизатор SQL сервер откровенно тупит при работе с SQL запросами. Он просто неверно выбирает план выполнения и вы после этого можете разбиться головой об стену, но в случае с Linq вы ничего сделать не сможете. В случае с SQL вы получаете больше гибкости. Иногда просто поменяешь немного SQL запрос и SQL сервер магически начинает работать быстрее, потому что сервер выбирает использование другого индекса и вы в шоколаде. В SQL вы можете использовать такую офигенную фишку как WITH и помогать оптимизатору понять вас. Transact-SQL очень гибкий и я не вижу смысла использовать какую-то дебильную надстройку над ним в виде Linq.

Microsoft уже создала дофига различных прослоек между программой и базами данных – ODBC, ADO, ADO.NET, DAO, LINQ, Entity Framework, но самая лучшая прослойка – это программист. От того, что вы используете что-то из этого, программа круче не становится. Но самое страшное, что MS делает эти прослойки далеко не всегда совместимыми. Тот же ADO.NET и ADO не смотря на идентичное название, не совместимы. И если завтра выйдет LINQ .NET, не факт, что он будет совместимым с текущим Linq и вполне возможно (история MS доказывает это), что вам придется выкинуть весь ваш LINQ код и писать все заново. А оно вам нужно?

Какое преимущество дает вам Linq, которого нет в SQL? Есть только одно преимущество – вы можете выбрать данные из базы данных в память локальной машины, а потом с помощью SQL фильтровать или сортировать данные. Но за такие вещи в средние века вас привязали бы ногами к столбу, а руками к лошади и порвали на хрен на части. Зачем это делать, когда нужно просто уметь писать SQL запросы так, чтобы сервер возвращал вам данные уже в том виде, который нужен без дополнительной фильтрации или сортировки на стороне клиента.

Соглашусь, бывают иногда случаи, когда нужна дополнительная обработка данных на стороне клиента. Особенно если нужно представить одни и те же данные дважды в разном виде и не хочется загружать сервер. Но такие случаи бывают не более чем 1%. У меня есть руки, чтобы сделать это без LINQ, зато мой код останется переносимым за счет использования SQL стандарта.

Единственное, когда я могу использовать Linq – когда нужно работать с XML данными, но только потому, что XML – это не сервер и он не поддерживает SQL.

Если кто-то не согласен со мной, то назовите мне преимущество LINQ, которое затмит его недостатки. Я всегда готов дискутировать и возможно кто-то сможет меня переубедить, что LINQ стоит того, чтобы использовать его уродство и убийство несовместимости.


Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым


Комментарии

Алексей

25 Февраля 2012

На мой взгляд, есть еще одна область, где преимущества LINQ дают возможность писать короче и наглядней, например, работа с коллекциями. К примеру, можно инициализировать массив с значением отличным от значения по умолчанию и затем вывести массив в две строки:

int[] arr =  Enumerable.Repeat(-1, 10).ToArray();
Console.WriteLine(string.Join(",",arr));

Есть и другие интересные методы для работы с коллекциями, напр. Intersect, Union, Except.


Bush

25 Февраля 2012

>эти уродливые конструкции .Where().Top().Skip().OrderBy().FirstOrDefault() и что там еще есть.
Конструкции весьма понятные и удобные, если использовать их к месту и с умом. В цитате налеплена бессмыслица, которая конечно же выглядит убого.

>Код становится непереносимым на другие платформы
Linq to Object, Linq to XML, Linq to Dataset работают как в MS .Net Framework, так и в Mono. Для Linq to Entity да, такой кроссплатформенности пока нет.

Linq to Entity я в своей работе не использовал, однако постоянно использую Linq to Object и Linq to XML - очень удобные технологии. Новичкам они поначалу могут показаться сложными и неудобными (мне порой жалуются на это), однако это до тех пор, пока они не разберутся в предмете. XPath 1.0/2.0 тоже не "пряник" на первый взгляд, но если приложить усилия и разобраться, то всё становится не таким уж и мрачным.


Денис

25 Февраля 2012

Я использовал её маленько(LINQ to Entities), а вообще Миш стоит тратить время на её изучение? Для
XML думаю можно поизучать LINQ/


Pushok

26 Февраля 2012

Не думаю, что отбрасывать LINQ только потому, что вам не нравится EF - хорошая идея, потому что технология достаточно мощная.
Кстати, вы не пробовали испльзовать sqk-подобный синтаксис в LINQ?
Ex: from myTable in Context.Tables
    select myTable.Field


Rejackt

26 Февраля 2012

Мне тоже кажется, что LINQ есть смысл применять для обработки только на стороне клиента - например с сервака выдернул через SQL-запрос в Datatable, а потом уже если нада "допилить" - то через LINQ...


Михаил Фленов

26 Февраля 2012

EF - хорошая идея, потому что технология достаточно мощная.


Что значит мощная? обладает какими-то супер возможностями, которые нельзя сделать просто в ADO.NET? На сколько я помню, это просто фреймворк и надстройка над ADO.NET, которая просто упрощает доступ к данным, генерирует для тебя классы, которые удобны для использования, но мощи там нет.

Кстати, вы не пробовали испльзовать sqk-подобный синтаксис в LINQ?


Его-то я и использовал и считаю уродливым. Он мне совершенно не понравился. Но если кому-то нравится, то я не против, ведь это всего лишь дело вкуса.


Pushok

27 Февраля 2012

Что значит мощная? обладает какими-то супер возможностями, которые нельзя сделать просто в ADO.NET? На сколько я помню, это просто фреймворк и надстройка над ADO.NET

Я имелл ввиду LINQ - мощная технология. EF можно и без LINQ использовать :)


Михаил Фленов

27 Февраля 2012

Ну в линке я тоже ничего мощного не увидел. Он все равно генерит SQL для доступа к данным. Так почему бы не писать сразу на SQL и не использовать различных программных передастов типа linq. Ведь основная его задача просто интегрировать язык запросов прямо в .NET и заниматься передастизмом - передавать C# мысли программиста в SQL.


Денис

27 Февраля 2012

Насколько я по помню, в LINQ to Entities есть возможность самому писать SQL-запросы на выборку, а результатом будет не набор данных, а набор сущностей. Разве это не мощь? Если нет, то выбирай
ado.net данные, и строки преобразуй в сущности. Если предметка сложная, геморрой тебе обеспечен. А
с LINQ to SQL согласен - это масло масленное....


Pushok

27 Февраля 2012

Ну в линке я тоже ничего мощного не увидел. Он все равно генерит SQL для доступа к данным. Так почему бы не писать сразу на SQL и не использовать различных программных передастов типа linq. Ведь основная его задача просто интегрировать язык запросов прямо в .NET и заниматься передастизмом - передавать C# мысли программиста в SQL.

Это лишь при работе с SQL запросами. А обработка коллекций, перечислений, возможность парсинга лямбд и дальнейшего их использования в LINQ?


Михаил Фленов

27 Февраля 2012

Если обрабатывать данные не базы данных, то используйте LINQ, если он нравится. Большинство программистов лучше чем то, что реализовано в LINQ все равно код не напишут.


Bush

27 Февраля 2012

Я часто использую Linq в следующих ситуациях (имея на руках некий IEnumerable<T>):
1. Нужно выполнить некоторую несложную операцию над всеми элементами перечисления, после чего результат обработки отфильтровать по некоторому условию и на основе результата создать перечисление экземпляров совершенно иного типа (например члены анонимного класса). "Несложную операцию" как правило юзаем в виде лямбда-выражения.
Как правило, код получается небольшой, в одну-три строки, вполне удобочитаемый, поскольку я использую не синтаксис "аля SQL", который на мой взгляд уродлив, а точечную нотацию - такой код читается последовательно и весьма понятен.

2. Просто выполнить некоторые действия над всеми или некоторыми, выбранными по определённому условию элементами перечисления.

3. Преобразовать список в массив, либо массив в словарь, либо др. подобное действо.

4. Очень удобно выполнять группирование, объединение, пересечение, выборку уникальных записей.

5. Весьма полезны и "ленивые" вычисления (надеюсь не нужно пояснять, что это такое).

6. Про удобство работы с XML даже пояснять не буду - оно весьма очевидно.

А вообще, мне кажется, что тема обусловлена тем, что автор (не в обиду сказано) не разобрался как следует в технологии LINQ. Нельзя судить о всём айсберге, видя лишь его маленький кончик, торчащий из воды, и при этом неудачно кем-то где-то применённый (причём не факт, что применённый грамотно).

имхо


Михаил Фленов

27 Февраля 2012

Последний раз говорю, используйте LINQ без проблем для чего угодно, но не для запросов к базам данных. То, что ты перечислил, это все работа с массивами данных (я надеюсь) не полученных из базы данных. Если данные можно обработать на стороне сервера нормальным SQL, то они должны обрабатываться на сервере нормальным SQL. Если для тебя перечисленное - это айсберг, то пусть будет айсбергом.

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

Прежде чем писать подобные комментарии, прочитайте пожалуйста еще раз что я написал. Я не рекомендвал, не рекомендую и не планирую рекомендовать эту фигню для написания запросов к базе данных. Если же вы решитись на это, то это ваши личные проблемы, я никому ничего не запрещаю.


Rub

27 Февраля 2012

Мальчик научился писать запросы к массивам данных и считает что это круто, теперь наверно на всех блогах и форумах будет показывать, какой он умный. Обработка массивов запросом – это пятнышко на айсберге LINQ, а все ваши (не думаю, что вам больше 20 лет) примеры это обработка структурированных данных в памяти. Когда начнёте работать программистом, то поймёте, что большинству требуется работать с базами данных и очень много времени уходит на написание запросов к базе данных. Обработка массивов информации и примеры, что вы описали нужны очень редко или если вы не знаете SQL.


n

27 Февраля 2012

А мне почему-то кажется, что это ромул. Такой же бред


Денис

27 Февраля 2012

Бреда не вижу. Просто человек любит синтаксис.

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

И самое главное - ты наверно не понял смысла LINQ. Я же сказал, что это передаст, который просто использует синтаксис запросов в коде. Ты пишешь запросы, но чаще всего (а может и всегда, тут я утверждать не буду, потому что не знаю всех тонкостей реализации) LINQ просто преобразовывает написанный тобой код в библиотечные функции других библиотек. Например, в случае с базами данных (прости, но уж с ними мне приходится работать чаще всего, поэтому описываю на их примере), твой запрос будет преобразован в SQL.

В случае с Linq to XML будут использоваться библиотечные функции .NET. Пойди на сайт Microsoft и посмотри, там черным по HTML странице написано: LINQ to XML uses the latest .NET Framework language capabilities and is comparable to an updated, redesigned Document Object Model (DOM) XML programming interface.

LiINQ - это действительно передаст (классное слово придумал Михаил), который преобразовывает запросы в библиотечные функции или в SQL. Тебе нравится этот синтаксис? Используй, какие претензии к другим? Ты думаешь, что если постиг LINQ к массивам, то постиг айсберг? Спешу тебя удивить, но основное предназначение LINQ - это как раз базы данных. Только если потом захочешь перенести свой код на C++/Java или что-то другое, не говори, что тебя не предупреждали, что LINQ - это дерьмо, которое использовать нужно аккуратно.


Преобразовать список в массив, либо массив в словарь, либо др. подобное действо.


Вот над этим ржал. Использовать LINQ для преобразования данных, это конечно жестоко. Спасибо, насмешил. Это точно айсберг, до которого я бы не додумался


Михаил Фленов

28 Февраля 2012

2 Bush

Давно не удалял комментарии, но тут выхода просто нет, потому что дискуссии нет. В твоем комментарии только одна мысль по теме:

Как я понял, под "дискуссией" здесь подразумевают "полное согласие с исходным текстом". Любое отклонение от обозначенной траектории провоцирует срачь со стороны некоторых "взрослых специалистов".


Перечитай еще раз мой пост и посмотри, о чем мы говорим:

Если кто-то не согласен со мной, то назовите мне преимущество LINQ, которое затмит его недостатки.


Назови преимущество и я с удовольствием продолжу твою дискуссию. Прежде чем писать это преимущество перечитай еще раз мой пост и заметь две основные идеи его - я не рекомендую использовать LINQ к базам данных и я не против использования LINQ to XML или к массивам. Если ты будешь опять писать, что я не разбираюсь в сути LINQ, потому что использование LINQ к массивам - это супер, то перечитай еще раз мой пост, потому что ты его явно не понял


n

28 Февраля 2012

Ну тут все ясно. Человек прочитал книгу, которая ему очень сильно понравилась. Но в книге по LINQ автор скорей всего решил не создавать базу данных, а показывал синтаксис на примере каких-то данных в памяти, поэтому Bush считает, что именно это айсберг

Преимущество LINQ - один и тот же синтаксис используется для вытаскивания данных из разных источников - базы данных (причем любой), XML или просто из массива. Ты можешь написать универсальный класс, который будет вытаскивать данные из любого источника.


Михаил Фленов

28 Февраля 2012

Да, это преимущество о котором можно  подискутировать. Я об этом не подумал, потому что мне не приходится писать такой код.

Я вообще не особый сторонник такой уж универсализации кода. Но если действительно встанет задача написать что-то подобное, то я согласен, LINQ может быть оправдан. Конечно если он действительно позволит написать такое. Вот на столько хорошо я LINQ не знаю, чтобы тут что-то противопоставить.


Михаил Фленов

28 Февраля 2012

Подумал еще раз и пришел к выводу - нет, для меня переносимость кода важнее. Твой класс будет непросто перенести на C++.

И я все же боюсь, что Microsoft завтра придумает новую фигню, которая будет несовместима с LINQ.


Михаил Фленов

28 Февраля 2012

Подумал еще немного, и решил добавить, что я бы не стал писать такой универсальности, даже если она возможна, но это мое мнение. А добавить хочу следующее (и даже хочу подчеркнуть) - если кто-то хочет, то может написать, я не против и криминала не вижу.


Николай

23 Марта 2012

Знаешь, Михаил, когда мне первый раз посоветовали LINQ и сказали, что это круто, я сразу сделал вывод, что LINQ-это возможность использования практически sql-запросов(Запросов, очень напоминающих sql-запросы) для доступа клюбому источнику данных. Придумано это для того, чтобы так себе программисты могли не разбираться, как работать с каждым из них. Представь, программист-новичок начинает свой путь. Чтобы работать с базами ему нужно освоить SQL, для работы c XML разобраться с его структурой, с массивами и коллекциями свои тонкости и свой код. А тут взяли и всучили в руки универсальный механизм. Теперь со всем этим разбираться необязательно.
Что я могу сказать, уровень прогрммистов вряд ли вырастет. Я знаю программистов, которые даже не догадываются, чем очередь отличается от стека. Может дойдет до того, что перестанут понимать разницу между XML и базой данных))


Игорь

20 Августа 2012

Я извиняюсь на некрокомментарий, но ваш блог нашел случайно буквально несколько дней назад, раньше читал ваши книги, и начал читать весь блог с обратном порядке.
В дискусию с LINQ просто не могу не ворватся.

Для чего я обычно использую Linq 2 SQL: когда нужно быстро сделать систему, для которой не сильно важны высокие нагрузки. В итоге я имею меньшую вероятность сделать ошибку при построении сложных запросов.

Вот пример одного сложного запроса, который использовался реально в одной из систем (небольшая система для отчетности, которую используют несколько пользователей):

from cl in dc.Clients
where !cl.Deleted
let balanceAdd = cl.Payments
    .Sum(x => (decimal?)(x.Sum * x.PaymentType.TOCoefClient)) ?? 0
let balanceSub = cl.Campaigns.SelectMany(c => c.Accounts)
    .Sum(acc => (decimal?)(acc.ReportsCount * acc.MiddleCost)) ?? 0
let incomeAdd = cl.Payments
    .Sum(x => (decimal?)(x.Sum * x.PaymentType.TOCoefMediaLead)) ?? 0
let incomeSub = (dc.Cards
    .Where(c => c.Account.Campaign.ClientID == cl.ID)
    .Sum(c => c.BuyPrice) ?? 0) +
    (dc.Coupons
    .Where(c => c.Account.Campaign.ClientID == cl.ID)
    .Sum(c => c.BuyPrice) ?? 0)
let adWordsAdd = (dc.Cards
    .Where(c => c.Account.Campaign.ClientID == cl.ID)
    .Sum(c => c.VolumePrice) ?? 0) +
    (dc.Coupons
    .Where(c => c.Account.Campaign.ClientID == cl.ID)
    .Sum(c => c.VolumePrice) ?? 0)
let middleSum = cl.Campaigns.SelectMany(c => c.Accounts)
    .Where(acc => acc.DateFrom.HasValue && acc.DateFrom.Value <= now && (!acc.DateTo.HasValue || acc.DateTo.Value >= now))
    .Sum(acc => (decimal?)acc.MiddleCost) ?? 0
let turnover = dc.ReportDatas
    .Where(rd => rd.Import.Account.Campaign.ClientID == cl.ID)
    .Sum(rd => (decimal?)rd.Cost) ?? 0
select new ClientDebtReportItem
{
    ID = cl.ID,
    Name = cl.Name,
    Balance = balanceAdd - balanceSub,
    Income = incomeAdd - incomeSub,
    AdWords = adWordsAdd - balanceSub,
    Turnover = turnover,
    MiddleSum = middleSum
};

Понять такой запрос намного проще (для тех кто знаком с LINQ), чем аналогичный SQL код, места он будет занимать куда больше, и поэтому вероятность сделать ошибку больше.

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


Linq - sucks

07 Июня 2017

Ничего хуже чем Linq нет на свете. А хотя нет, есть... софт состоящий из кучи npm пакетов... Вообще программирование скатывается постепенно в профессию сборщика софта из пакетов. Причем такой софт всегда глючный медленный, код у него не читаемый и его постоянно переписывают.


Добавить Комментарий

Еще что-нибудь

Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.

О блоге

Программист, автор нескольких книг серии глазами хакера и просто блогер. Интересуюсь безопасностью, хотя хакером себя не считаю

Обратная связь

Без проблем вступаю в неразборчивые разговоры по e-mail. Стараюсь отвечать на письма всех читателей вне зависимости от страны проживания, вероисповедания, на русском или английском языке.

Пишите мне