Является ли LinqToSQL достаточно мощным? Не проще ли создать более мощный, но не менее гибкий интерфейс? - PullRequest
0 голосов
/ 12 марта 2009

В предыдущем вопросе я спросил, являются ли библиотеки ORM неоптимальными решениями и получил много хороших отзывов. Как я уже думал об этой проблеме, я пришел к выводу, что основное преимущество LinqToSQL (сейчас) и обещание LinqToEntities (в будущем) заключается в их способности уменьшить «несоответствие» между процедурным кодом и SQL. Учитывая ограничения LinqToSQL как полноценного языка запросов данных, я не склонен соглашаться с тем, что его преимущества выходят далеко за рамки этого, но я хотел бы узнать мнение других.

Для начала, что я подразумеваю под "несоответствием" между процедурным кодом и SQL? Если вы когда-либо разрабатывали приложение для базы данных, то вы, вероятно, уже знакомы (и устали от) шагов, необходимых для взаимодействия с базой данных: установите все параметры, введите команду SQL, а затем вручную преобразуйте ожидаемые результаты обратно в переменные или экземпляры, используемые в коде.

LinqToSql значительно облегчает эту задачу за счет использования «беглых» интерфейсов, лямбда-выражений, методов расширения и т. Д. Конечный результат заключается в том, что легко вставлять собственные скалярные типы C # в вызов поиска данных и автоматически генерировать собственные Экземпляры класса C # Возьмите этот пример с веб-сайта 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);

Очень круто!

Так в чем же проблема?

Что ж, как я указывал в статье, на которую сверху ссылается, есть ряд проблем. Самый большой showtopper для меня заключался в том, что любой, кто минимально компетентен в SQL, немедленно преодолеет контрольно-пропускные пункты. Дело не только в том, что многие конструкции, созданные в качестве альтернатив SQL, незнакомы или даже неуклюжи (Group By? Мы говорим Ugly в LinqToSql). Большая проблема заключается в том, что существует ряд распространенных конструкций, которые просто не поддерживаются изначально (например, DateDiff). В лучшем случае вы можете «выйти» из Linq и отправить код SQL в поток вызовов Linq.

Итак, не лучше ли просто встраивать SQL в C # (или 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 и вводит первый параметр, Append указывает на дополнительный SQL , ParamVal просто вводит значение параметра, соответствующее параметру SQL, найденному в предыдущей строке, а ReturnList делает магию, необходимую для преобразования в класс. Обратите внимание, что это просто SQL: объединения тривиальны, DateDiff (или любая другая конструкция SQL) поддерживается и т. Д. Мы можем проверить это в окне SQL, а затем просто вырезать и вставить в наш код, разбив его соответствующим образом для ввода наши параметры. Это не может быть проще.

Теперь, базовая конструкция, показанная выше, мне кажется невероятно простой, и она может обрабатывать ЛЮБУЮ конструкцию SQL, используя знания SQL, которые у меня уже есть . Мне пришлось использовать некоторое отражение и некоторые другие классные новые конструкции C # 3, чтобы заставить вызовы ReturnList (и аналогичные) работать, но в целом это было довольно просто. Я также добавил несколько наворотов, чтобы сделать интерфейс более плавным. Итак, вот мой вопрос, и где я хотел бы услышать комментарии от сообщества:

Зачем мне когда-либо овладевать тонкостями LinqToEntities или даже нести накладные расходы на LinqToSql? Разве это не дает мне все, что дает мне LinqToSql, и даже больше? Разве он не охватывает даже LinqToEntities, за исключением экзотических отображений реляционных объектов?

Обновление : Хэмиш Смит ниже утверждает, что LINQ может когда-нибудь стать полностью мощным языком манипулирования данными, настолько мощным, что SQL даже не понадобится. Это важный переломный момент, который я не обсуждал, но с которым согласен. Суть моей позиции заключается в том, что, хотя у LinqToSql есть некоторые практические преимущества, он все равно отстает на 1047 * далеко от цели Хэмиша. Это очень реальный и существенный недостаток.

Хэмиш также правильно утверждает, что я все еще работаю со встроенным SQL - я не "решил" проблему. Для меня, однако, это функция , а не ошибка. SQL по-прежнему намного лучше выбирает реляционные данные и манипулирует ими (а это, в конце концов, то, с чем мы работаем), что я хочу, чтобы мог использовать его для разработки моего решения. Я утверждаю, что встроенный SQL - это не проблема, а несоответствие импеданса между ним и C #. Тем не менее, используя новые вдохновленные Linq функции C # 3, я могу в значительной степени устранить это «несоответствие импеданса» и получить лучшее из обоих миров.

Ответы [ 6 ]

2 голосов
/ 13 марта 2009

Так что, не лучше ли просто встраивать SQL в C # (или VB) способами, которые позволяют вы можете свободно заявить свой SQL, но это также дать вам простое вложение параметров и автоматическое преобразование в родной классы?

То, что я обычно делаю, очень близко к этому. Я пишу SQL в хранимой процедуре, поэтому я получаю свободу реального SQL. В C # я использую DBML Линка для доступа к хранимым процедурам естественным образом. Это похоже на лучшее из обоих миров.

Реальное решение выглядит для меня еще проще: встроить SQL в код C # и заставить компилятор генерировать сильные классы. Если бы Visual Studio поддерживал это, я сомневаюсь, что кто-то использовал бы что-нибудь еще.

(Всегда есть люди, пытающиеся создать Entity Frameworks и «архитектуру», которые устраняют потребность в SQL. Насколько я знаю, это никогда не срабатывало, хотя бы потому, что результат значительно сложнее поддерживать и очень медленно.)

1 голос
/ 26 марта 2009

var q = DataContext.ExecuteQuery ("SELECT * FROM и т. Д.") Обычно выполняет довольно хорошую работу.

1 голос
/ 13 марта 2009

Что вы предлагаете с вашим классом запросов, так это то, что вы все еще встраиваете SQL непосредственно в код приложения. Что вы получаете с помощью решения LINQ + ORM, так это то, что код приложения никогда не содержит SQL. У вас все еще есть несоответствие и отвлечение от работы над кодом. Вы упоминаете об этом в своем посте:

Мы можем проверить это в окне SQL и затем просто вырезать и вставить в наш код, разбив его по мере необходимости, чтобы войти наши параметры. Это не может быть проще.

То, что пытается дать нам синтаксис LINQ, это запросы в качестве первоклассных граждан в коде. Да, некоторые вещи неуклюжи, некоторые вещи могут быть еще не совсем правильными, но заявленная цель LINQ состоит в том, чтобы интегрировать код запроса и приложения до такой степени, чтобы не было несвязного. Похоже, это не то, что вам нужно, поэтому, возможно, встраивание SQL в виде строковых литералов, непрозрачных для компилятора и среды выполнения, будет работать лучше для вас. Мы знаем, что это можно заставить работать, мы делали это годами.
Другое преимущество заключается в том, что оператор LINQ не будет подвержен конкретным изменениям поставщика (это проблема поставщика LINQ). В результате вы можете получить строку SQL, которую вы передаете qry.Command (), привязанную к конкретной базе данных.

1 голос
/ 12 марта 2009

linq2sql имеет встроенную поддержку подкачки и строго типизирован.

Вы можете избежать отслеживания сущностей, если не будете его использовать.

Вы можете вызывать функции sql, заключив их в метод.

Если вы используете отслеживание сущностей, вы можете легко пакетировать несколько вызовов манипулирования данными (делает это автоматически, то есть вызов SubmitChanges). Таким образом, вы не попадете в базу данных 15 раз, чтобы выполнить 5 вставок и 10 обновлений.

Это также удобно, когда вы хотите получить структурированную информацию, например:

var someInfo = from s in Context.Somethings
               select new SomeInfo
               {
                   AField = s.SomeColumn,
                   RelatedStuff = s.RelatedInfo.Where(someconditionhere)
               };

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

1 голос
/ 12 марта 2009

Я думаю, что это излишне, и LinqToSQL, и LinqToEntities. Я выбрал минималистичный подход. Я разработал DAL, который использует DTO и отражает его свойства для генерации SQL на лету. Это работает в 95% случаев, когда я не нуждаюсь и не хочу думать о SQL. Для всех остальных случаев мой DAL позволяет мне писать любой SQL, который я хочу, и возвращает либо DataSet, либо, если ему дан DTO, он заполняет его результатами. Это также позволяет вызывать хранимые процедуры с той же концепцией, возвращая DataSet или DTO. Для меня это работает очень хорошо, и мне не нужно видеть SQL, если я не хочу.

0 голосов
/ 13 марта 2009

На данный момент Я не фанат Entity Framework, но 4.0 выглядит намного лучше. Я не уверен, что это такое большое изменение, как Vista против Windows 7, но определенно лучше.

Сейчас я считаю, что LINQ-to-SQL охватывает большинство вещей, которые мне регулярно нужны. Черт возьми, даже если я просто использую его для подключения хранимых процедур без необходимости писать код параметра, это мое преимущество. Я считаю, что материал CRUD отлично подходит для простой обработки ортогональных данных. Для более сложных сценариев мне нравятся UDF и т. Д., Которые LINQ-to-SQL прекрасно поддерживает.

Пока вы скрываете это в хранилище , вы даже не рисуете себя в углу.

Re datediff - вы смотрели на SqlMethods?

...