В предыдущем вопросе я спросил, являются ли библиотеки ORM субоптимальными решениями и получили много отличных отзывов. Как я уже думал о проблеме, я пришел к выводу, что основное преимущество LinqToSQL (сейчас) и обещание LinqToEntities (в будущем) заключается в их способности сократить "несоответствие" между процедурным кодом и SQL. Учитывая ограничения LinqToSQL как полного языка запросов данных, я не склонен согласиться с тем, что его преимущества намного превосходят его, но я хотел бы узнать мнение других.
Чтобы начать, что я имею в виду под "несоответствием" между процедурным кодом и SQL? Если вы когда-либо разрабатывали приложение базы данных, то вы, вероятно, знакомы с (и устали) от шагов, необходимых для взаимодействия с базой данных: настройте все параметры, введите команду SQL, а затем вручную преобразуйте ожидаемые результаты обратно в переменные или экземпляры, используемые в коде.
LinqToSql делает это намного проще с помощью "плавных" интерфейсов, лямбда-выражений, методов расширения и т.д. Конечным результатом является то, что легко вытащить собственные скалярные типы С# в запрос поиска данных и легко автоматически генерировать собственные С#. Возьмите этот пример с веб-сайта MS:
var q =
from c in db.Customers
where c.City == "London"
select c;
foreach (var cust in q)
Console.WriteLine("id = {0}, City = {1}",cust.CustomerID, cust.City);
Очень круто!
Итак, в чем проблема?
Хорошо, как я указал в статье, связанной с наверху, есть ряд проблем. Самый большой шоу-стоппер для меня заключался в том, что любой, кто минимально компетентен в SQL, сразу же попадает в блокпосты. Дело не только в том, что многие из конструкций, созданных как альтернативы SQL, незнакомы или даже неуклюжи (Group By? Мы говорим Ugly в LinqToSql). Большая проблема заключается в том, что существует ряд общих конструкций, которые просто не поддерживаются изначально (например, DateDiff). В лучшем случае вы можете "выйти из" Linq и отправить код SQL в поток вызовов Linq.
Итак, не лучше ли просто встраивать SQL в С# (или VB) способами, которые позволяют свободно указывать ваш SQL, но также дают вам легкое вложение параметров и автоматическое преобразование в родные классы? Например, если мы реализуем только шесть функций в одном классе, мы можем написать что-то вроде этого (где qry - это экземпляр нашего класса запросов):
var ListOfEnrollees =
qry.Command("Select b.FirstName, b.LastName, b.ID From ClassEnroll a inner join Folder b on (a.ClientID = b.ClientID) ")
.Where ("a.ClassID", classID)
.AND()
.Append("(DateDiff(d, a.ClassDate, @ClassDate) = 0) Order By LastName;")
.ParamVal(classDate)
.ReturnList<EnrollListMemberData>();
Команда просто заставляет нас не собирать инструкцию SQL, где начинается наше предложение SQL Where и вводится первый параметр, добавляет tacks на большее количество SQL, ParamVal просто вводит значение параметра в соответствие с параметром SQL, найденным в предыдущей строке, и ReturnList делает магию, необходимую для преобразования в класс. Обратите внимание, что это просто SQL: объединения тривиальны, поддерживается DateDiff (или любая другая конструкция SQL) и т.д. Мы можем протестировать его в окне SQL, а затем просто вырезать и вставлять в наш код, разбивая его по мере необходимости для ввода наши параметры. Это не может быть проще.
Теперь базовая конструкция, показанная выше, кажется мне противным, и она может обрабатывать любую конструкцию SQL, используя знания SQL, которые у меня уже есть. Мне пришлось использовать некоторое отражение и некоторые другие интересные новые конструкторы С# 3, чтобы сделать вызовы ReturnList (и подобных), но в целом это было довольно просто. Я также добавил несколько колоколов и свистов, чтобы сделать интерфейс более свободным. Итак, вот мой вопрос и где мне бы хотелось услышать комментарии сообщества:
Почему мне когда-либо понадобилось освоить тонкости LinqToEntities или даже нанести накладные расходы LinqToSql? Разве это в значительной степени не дает мне все, что LinqToSql дает мне и больше? Не покрывает ли он даже LinqToEntities, за исключением экзотических привязок к сопоставлениям объектов?
Обновить. Хэмиш Смит утверждает ниже, что LINQ может когда-нибудь быть полностью способным манипулировать данными, настолько мощным, что SQL даже не нужен. Это важный аргумент, который я не обсуждал, но с которым согласен. Суть моей позиции заключается в том, что, хотя у LinqToSql есть некоторые практические преимущества, она все еще далеко отстает от цели Хэмиша. Это очень реальный и существенный недостаток.
Хэмиш также правильно утверждает, что я все еще работаю со встроенным SQL - я не "решил" проблему. Для меня, однако, это особенность, а не ошибка. SQL по-прежнему гораздо лучше выбирает и обрабатывает реляционные данные (а это, в конце концов, то, с чем мы работаем), которые я хочу использовать для создания моего решения. Я утверждаю, что встроенный SQL не является проблемой, так как импедансное несоответствие между ним и С#. Однако, используя новые, созданные Linq функции С# 3, я могу в значительной степени устранить это "несоответствие импеданса" и получить лучшее из обоих миров.