Еще когда появился 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 стоит того, чтобы использовать его уродство и убийство несовместимости.
Понравилось? Кликни Лайк, чтобы я знал, какой контент более интересен читателям. Заметку пока еще никто не лайкал и ты можешь быть первым
На мой взгляд, есть еще одна область, где преимущества LINQ дают возможность писать короче и наглядней, например, работа с коллекциями. К примеру, можно инициализировать массив с значением отличным от значения по умолчанию и затем вывести массив в две строки:
int[] arr = Enumerable.Repeat(-1, 10).ToArray();
Console.WriteLine(string.Join(",",arr));
Есть и другие интересные методы для работы с коллекциями, напр. Intersect, Union, Except.
>эти уродливые конструкции .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 тоже не "пряник" на первый взгляд, но если приложить усилия и разобраться, то всё становится не таким уж и мрачным.
Я использовал её маленько(LINQ to Entities), а вообще Миш стоит тратить время на её изучение? Для
XML думаю можно поизучать LINQ/
Не думаю, что отбрасывать LINQ только потому, что вам не нравится EF - хорошая идея, потому что технология достаточно мощная.
Кстати, вы не пробовали испльзовать sqk-подобный синтаксис в LINQ?
Ex: from myTable in Context.Tables
select myTable.Field
Мне тоже кажется, что LINQ есть смысл применять для обработки только на стороне клиента - например с сервака выдернул через SQL-запрос в Datatable, а потом уже если нада "допилить" - то через LINQ...
Ну в линке я тоже ничего мощного не увидел. Он все равно генерит SQL для доступа к данным. Так почему бы не писать сразу на SQL и не использовать различных программных передастов типа linq. Ведь основная его задача просто интегрировать язык запросов прямо в .NET и заниматься передастизмом - передавать C# мысли программиста в SQL.
Насколько я по помню, в LINQ to Entities есть возможность самому писать SQL-запросы на выборку, а результатом будет не набор данных, а набор сущностей. Разве это не мощь? Если нет, то выбирай
ado.net данные, и строки преобразуй в сущности. Если предметка сложная, геморрой тебе обеспечен. А
с LINQ to SQL согласен - это масло масленное....
Если обрабатывать данные не базы данных, то используйте LINQ, если он нравится. Большинство программистов лучше чем то, что реализовано в LINQ все равно код не напишут.
Я часто использую Linq в следующих ситуациях (имея на руках некий IEnumerable<T>):
1. Нужно выполнить некоторую несложную операцию над всеми элементами перечисления, после чего результат обработки отфильтровать по некоторому условию и на основе результата создать перечисление экземпляров совершенно иного типа (например члены анонимного класса). "Несложную операцию" как правило юзаем в виде лямбда-выражения.
Как правило, код получается небольшой, в одну-три строки, вполне удобочитаемый, поскольку я использую не синтаксис "аля SQL", который на мой взгляд уродлив, а точечную нотацию - такой код читается последовательно и весьма понятен.
2. Просто выполнить некоторые действия над всеми или некоторыми, выбранными по определённому условию элементами перечисления.
3. Преобразовать список в массив, либо массив в словарь, либо др. подобное действо.
4. Очень удобно выполнять группирование, объединение, пересечение, выборку уникальных записей.
5. Весьма полезны и "ленивые" вычисления (надеюсь не нужно пояснять, что это такое).
6. Про удобство работы с XML даже пояснять не буду - оно весьма очевидно.
А вообще, мне кажется, что тема обусловлена тем, что автор (не в обиду сказано) не разобрался как следует в технологии LINQ. Нельзя судить о всём айсберге, видя лишь его маленький кончик, торчащий из воды, и при этом неудачно кем-то где-то применённый (причём не факт, что применённый грамотно).
имхо
Последний раз говорю, используйте LINQ без проблем для чего угодно, но не для запросов к базам данных. То, что ты перечислил, это все работа с массивами данных (я надеюсь) не полученных из базы данных. Если данные можно обработать на стороне сервера нормальным SQL, то они должны обрабатываться на сервере нормальным SQL. Если для тебя перечисленное - это айсберг, то пусть будет айсбергом.
Я не против использования в перечисленных тобой случаях, потому что код действительно получится небольшим, а если не знаешь базовых алгоритмов, то еще и быстрее. Но даже зная алгоритмы, каждый раз изобретать колесо не нужно, когда есть LINQ и хочется его использовать.
Прежде чем писать подобные комментарии, прочитайте пожалуйста еще раз что я написал. Я не рекомендвал, не рекомендую и не планирую рекомендовать эту фигню для написания запросов к базе данных. Если же вы решитись на это, то это ваши личные проблемы, я никому ничего не запрещаю.
Мальчик научился писать запросы к массивам данных и считает что это круто, теперь наверно на всех блогах и форумах будет показывать, какой он умный. Обработка массивов запросом – это пятнышко на айсберге LINQ, а все ваши (не думаю, что вам больше 20 лет) примеры это обработка структурированных данных в памяти. Когда начнёте работать программистом, то поймёте, что большинству требуется работать с базами данных и очень много времени уходит на написание запросов к базе данных. Обработка массивов информации и примеры, что вы описали нужны очень редко или если вы не знаете SQL.
А мне почему-то кажется, что это ромул. Такой же бред
Бреда не вижу. Просто человек любит синтаксис.
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 - это дерьмо, которое использовать нужно аккуратно.
2 Bush
Давно не удалял комментарии, но тут выхода просто нет, потому что дискуссии нет. В твоем комментарии только одна мысль по теме:
Ну тут все ясно. Человек прочитал книгу, которая ему очень сильно понравилась. Но в книге по LINQ автор скорей всего решил не создавать базу данных, а показывал синтаксис на примере каких-то данных в памяти, поэтому Bush считает, что именно это айсберг
Преимущество LINQ - один и тот же синтаксис используется для вытаскивания данных из разных источников - базы данных (причем любой), XML или просто из массива. Ты можешь написать универсальный класс, который будет вытаскивать данные из любого источника.
Да, это преимущество о котором можно подискутировать. Я об этом не подумал, потому что мне не приходится писать такой код.
Я вообще не особый сторонник такой уж универсализации кода. Но если действительно встанет задача написать что-то подобное, то я согласен, LINQ может быть оправдан. Конечно если он действительно позволит написать такое. Вот на столько хорошо я LINQ не знаю, чтобы тут что-то противопоставить.
Подумал еще раз и пришел к выводу - нет, для меня переносимость кода важнее. Твой класс будет непросто перенести на C++.
И я все же боюсь, что Microsoft завтра придумает новую фигню, которая будет несовместима с LINQ.
Подумал еще немного, и решил добавить, что я бы не стал писать такой универсальности, даже если она возможна, но это мое мнение. А добавить хочу следующее (и даже хочу подчеркнуть) - если кто-то хочет, то может написать, я не против и криминала не вижу.
Знаешь, Михаил, когда мне первый раз посоветовали LINQ и сказали, что это круто, я сразу сделал вывод, что LINQ-это возможность использования практически sql-запросов(Запросов, очень напоминающих sql-запросы) для доступа клюбому источнику данных. Придумано это для того, чтобы так себе программисты могли не разбираться, как работать с каждым из них. Представь, программист-новичок начинает свой путь. Чтобы работать с базами ему нужно освоить SQL, для работы c XML разобраться с его структурой, с массивами и коллекциями свои тонкости и свой код. А тут взяли и всучили в руки универсальный механизм. Теперь со всем этим разбираться необязательно.
Что я могу сказать, уровень прогрммистов вряд ли вырастет. Я знаю программистов, которые даже не догадываются, чем очередь отличается от стека. Может дойдет до того, что перестанут понимать разницу между XML и базой данных))
Я извиняюсь на некрокомментарий, но ваш блог нашел случайно буквально несколько дней назад, раньше читал ваши книги, и начал читать весь блог с обратном порядке.
В дискусию с 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 нет на свете. А хотя нет, есть... софт состоящий из кучи npm пакетов... Вообще программирование скатывается постепенно в профессию сборщика софта из пакетов. Причем такой софт всегда глючный медленный, код у него не читаемый и его постоянно переписывают.
Хотите найти еще что-то интересное почитать? Можно попробовать отфильтровать заметки на блоге по категориям.