Является ли встроенный SQL по-прежнему плохой практикой, когда у нас есть микро ORM?

26

Это немного открытый вопрос, но я хотел получить некоторые мнения, так как я вырос в мире, где встроенные SQL-скрипты были нормой, тогда мы все были хорошо осведомлены о проблемах, связанных с SQL-инъекциями, и о том, насколько хрупким был SQL, когда делать струнные манипуляции повсюду.

Затем наступил рассвет ORM, когда вы объясняли запрос ORM и позволяли ему генерировать собственный SQL, который во многих случаях был неоптимальным, но безопасным и простым. Еще одна хорошая вещь об ORM или уровнях абстракции базы данных заключалась в том, что SQL был сгенерирован с учетом его механизма базы данных, поэтому я мог использовать Hibernate / Nhibernate с MSSQL, MYSQL, и мой код никогда не менялся, это была просто деталь конфигурации.

Теперь перенесемся в текущий день, когда кажется, что Micro ORM выигрывает у большего числа разработчиков. Мне было интересно, почему мы, казалось бы, сделали разворот по всей теме sql.

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

Так что же думают люди по этому поводу? Я использую Dapper в качестве моего микро ORM в этом случае и NHibernate в качестве моего обычного ORM в этом сценарии, однако большинство в каждой области довольно похожи.

Что я называю встроенным SQLэто строки SQL в исходном коде. Раньше в исходном коде проходили дебаты по строкам SQL, что отвлекало от фундаментальной цели логики, поэтому статически типизированные запросы в стиле linq стали настолько популярными, что их все еще только один язык, но, скажем, с C # и Sql на одной странице, у вас есть 2 языка смешались в вашем исходном коде. Просто чтобы уточнить, SQL-инъекция - это только одна из известных проблем с использованием строк sql, я уже упоминал, что вы можете не допустить этого при запросах на основе параметров, однако я выделяю другие проблемы с внедрением SQL-запросов в ваш исходный код, таких как отсутствие абстракции DB Vendor, а также потеря любого уровня захвата ошибок времени компиляции при запросах на основе строк, - это все проблемы, которые нам удалось обойти с появлением ORM с их функциональностью запросов более высокого уровня,

Таким образом, я менее сконцентрирован на отдельных выделенных проблемах, и тем больше картина того, что теперь становится более приемлемым снова иметь строки SQL непосредственно в исходном коде, поскольку большинство микро-ORM используют этот механизм.

Вот аналогичный вопрос, который имеет несколько разных точек зрения, хотя больше о встроенном SQL без контекста микроорганизмов:

/programming/5303746/is-inline-sql-hard-coding

Grofit
источник
1
Как вы думаете, вы могли бы перефразировать вопрос таким образом, чтобы он не спрашивал мнение? Опрос на мнения не вписывается в формат вопросов и ответов Stack Exchange.
Вы всегда можете абстрагировать свои запросы «Micro ORM» в отдельный класс, где при необходимости вы меняете запросы, выполняемые при изменении вашей СУБД.
CodeCaster
не слышал термин "микро ОРМ". Вы имеете в виду ORM, которые не пытаются полностью перенять SQL, или это что-то другое?
Хавьер
не обращайте внимания, после небольшого поиска в Google, кажется, вещь .net.
Хавьер
1
@GrandmasterB: объясните почему в ответе. Я в значительной степени обошел эту проблему в своем ответе, поскольку считаю, что это вопрос компромиссов.
Роберт Харви

Ответы:

31

То, что вы описываете как «встроенный SQL», на самом деле следует называть «конкатенацией строк без параметризации», и вам не нужно делать это для безопасного использования Micro ORM.

Рассмотрим этот пример Dapper:

string sql = "SELECT * from user_profile WHERE FirstName LIKE @name;";
var result = connection.Query<Profile>(sql, new {name = "%"+name+"%"});

Он полностью параметризован, хотя происходит конкатенация строк. Видите знак @?

Или этот пример:

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", 
          new { Age = (int?)null, Id = guid });

что примерно эквивалентно следующему коду ADO.NET:

List<Dog> dog = new List<Dog>();
using(var cmd = connection.CreateCommand()) {
    cmd.CommandText = "select Age = @Age, Id = @Id";
    cmd.Parameters.AddWithValue("Age", DBNull.Value);
    cmd.Parameters.AddWithValue("Id", guid);
    using(var reader = cmd.ExecuteReader()) {
        while(reader.Read()) {
            int age = reader.ReadInt32("Age");
            int id = reader.ReadInt32("Id");
            dog.Add(new Dog { Age = age, Id = id });
        }
    }
}

Если вам нужно больше гибкости, Dapper предоставляет шаблоны SQL и AddDynamicParms()функцию. Все SQL-инъекции безопасны.

Так зачем использовать строки SQL в первую очередь?

Ну, по тем же причинам, вы бы использовали пользовательский SQL в любом другом ORM. Возможно, ORM генерирует код неоптимального SQL, и вам нужно его оптимизировать. Может быть, вы хотите сделать что-то, что сложно сделать в ORM изначально, например, UNIONs. Или, может быть, вы просто хотите избежать сложности генерации всех этих прокси-классов.

Если вы действительно не хотите писать строку SQL для каждого метода CRUD в Dapper (кто это делает?), Вы можете использовать эту библиотеку:

https://github.com/ericdc1/Dapper.SimpleCRUD/

Это даст вам чрезвычайно простой и понятный CRUD, но при этом даст вам гибкость рукописных операторов SQL. Помните, что приведенный выше пример ADO.NET был способом, которым все это делали до появления ORM; Dapper - это всего лишь тонкий шпон.

Роберт Харви
источник
Хорошие примеры, я уже упоминал, что вы можете обойти SQL-инъекцию с помощью параметров, так как это всего лишь часть более крупного вопроса, а также добавили правку, поясняющую, что я имею в виду, когда я использую термин inline sql .
Грофит
Я добавил некоторые детали в свой ответ.
Роберт Харви,
2
+1 за информацию о SimpleCRUD не знал, что это существовало.
Грофит
В Java вы найдете Mybatis, который является более легким, чем Hibernate или EclipseLink и. Его путь заключается в предопределенных предложениях в XML (вместо жесткого кодирования в коде). Он также добавляет некоторые интересные функции в качестве предварительных условий для улучшения окончательного SQL. Недавно мы использовали API-интерфейс с довольно высоким уровнем параллелизма и не сложным бизнесом, и он отлично работал.
Laiv
2

Мне нравится sql , и я терпеть не могу видеть его разбитым на строковые литералы, поэтому я написал небольшое расширение VS, чтобы вы могли работать с реальными файлами sql в проектах c #. Редактирование sql в своем собственном файле дает вам intellisense для столбцов и таблиц, проверку синтаксиса, выполнение теста, планы выполнения и все остальное. Когда вы сохраняете файл, мое расширение генерирует классы-обёртки c #, поэтому вы никогда не пишете ни строки кода соединения, ни кода команды, ни параметра, ни кода считывателя. Все ваши запросы параметризованы, потому что другого пути нет, и вы сгенерировали репозитории и POCO для модульного тестирования с intellisense для ваших входных параметров и ваших результатов.

И я добавил бесплатные ножи для стейка ... Когда специалисту нужно прийти и переделать sql вашего разработчика, она ищет настоящий файл sql и не нуждается в прикосновении к C #. Когда она возвращается и приводит в порядок БД, удаляя некоторые столбцы, ссылки на отсутствующие столбцы сразу же появляются как ошибки компиляции в c #. База данных становится похожим на другой проект в вашем решении, который вы можете взломать, его интерфейс можно обнаружить в коде. Если решение компилируется, вы знаете, что все ваши запросы работают. Нет ошибок во время выполнения из-за неправильных приведений, неправильных имен столбцов или неправильных запросов.

Оглядываясь назад, мы безумно верим, что в 2016 году это самая крутая вещь в доступе к данным. Генерация msil во время выполнения умна, но все ошибки являются ошибками во время выполнения, а манипуляции со строками, как и манипуляции со строками для любых других целей, требуют много времени, хрупки и подвержены ошибкам. И как это может быть Сухим, чтобы повторять имена столбцов в вашем POCO, которые вы должны писать и поддерживать вручную.

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

bbsimonbb
источник
Кажется, вы много думаете о своем маленьком «нововведении», но чем это отличается от, скажем, ExecuteStoreQuery или ExecuteStoreCommand в Entity Framework?
Роберт Харви
Я не вхожу в дебаты EF или SQL. Моя вещь для людей, которые хотят использовать SQL. Таким образом, как способ выполнения SQL, ExecuteStoreQuery () будет заполнять ваши POCO для вас, но вам все равно нужно определить свои POCO, судя по всему? И это не поможет вам поместить sql в файл или создать ваши параметры. Ваш запрос не обнаруживается ни в коде, ни в тестируемом. Удаление столбцов не приведет к ошибкам компиляции в вашем приложении. Я мог бы продолжать, но я боюсь, что я повторяюсь :-) Возможно, вы могли бы занять 3 минуты, чтобы посмотреть видео на YouTube. Это по-французски, выключи звук! Английский приходит.
bbsimonbb
EF вполне способен генерировать все POCO автоматически. Что мне здесь не хватает? Настоящая инновация Dapper и Massive заключается в том, что вам совсем не нужны POCO; Вы можете просто использовать dynamic.
Роберт Харви
Я почти ничего не знаю об EF. ExecuteStoreQuery () заполнит сущность. Будет ли он генерировать сущность из запроса . Сущности генерируются из объектов БД (или наоборот), а не из запросов. Если ваш запрос не соответствует существующему объекту, вы должны написать свой POCO, нет?
bbsimonbb
1
:-) Должен сказать, что я становлюсь чувствительным к обвинениям в рекламе, когда я свободно делюсь своей лучшей идеей. Вот мой последний бит агрессивного коммерциализма. К 3 минуте вы должны знать, нахожусь ли я на что-то или нет.
bbsimonbb
1

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

Кайл СП
источник