Лучшая практика для запроса данных из MS SQL Server в C #?

9

Каков наилучший способ запроса данных с MS SQL Server в C #?

Я знаю, что это не очень хорошая практика - иметь SQL-запрос в коде.

Это лучший способ создать хранимую процедуру и вызвать ее из C # с параметрами?

using (var conn = new SqlConnection(connStr))
using (var command = new SqlCommand("StoredProc", conn) { CommandType = CommandType.StoredProcedure }) {
   conn.Open();
   command.ExecuteNonQuery();
   conn.Close();
}
Bruno
источник
8
«Я знаю, что не стоит использовать SQL-запрос в коде». - Бессмысленно.
GrandmasterB
4
Вам не нужно вызывать conn.Close (), если вы создали его в блоке using. Весь смысл использования блока состоит в том, чтобы имитировать стиль очистки деструктора в C ++. Элегантная уборка с более цивилизованного возраста. Не такой случайный или неуклюжий, как стиль try-catch.
Лорд Тидус
2
FYI. Хранимые процедуры также являются «кодом». Весь смысл хранимых процедур состоял в том, чтобы позволить смешивать процедурный код с SQL на основе множественного стиля. Таким образом, у вас будет запрос в коде независимо. Для приложений с очень большими объемами иногда лучше выполнять логику вне базы данных, чтобы обеспечить горизонтальное масштабирование путем добавления серверов. Если вы можете поддерживать одну БД, но многосерверную для логики, тогда масштабирование становится намного проще.
Лорд Тидус
@GrandmasterB у нас есть значительное количество встроенного SQL в C # (наш C # LOC сейчас около 2 миллионов) - и 6 лет спустя он снова начинает кусать нас, потому что теперь нам нужно выследить этот встроенный SQL (недавно мы наняли эксперта по SQL - так мы делаем твики производительности). Поверьте мне: вы никогда не знаете, насколько большим станет ваше приложение и как все изменится в будущем. Храните разные языки в разных файлах - даже если вы просто делегируете их для манифестирования ресурсов. Вы также можете // SQLCODEэто сделать - но вы должны помнить, чтобы сделать это.
Джонатан Дикинсон
1
@JonathanDickinson, если хотите, используйте хранимые процедуры. Я много раз говорил, что они полезны, когда у вас разные базы кода, работающие с одной и той же базой данных. Но только потому , что они полезны в некоторых случаях оленьей кожи автоматически сделать не используя их «плохую практику» все время . Если использование операторов SQL напрямую не вызывает проблемы, то это не плохая практика для этого приложения.
GrandmasterB

Ответы:

10

Использование хранимых процедур является одним из способов и широко используется в течение многих лет.

Более современный способ взаимодействия с базами данных SQL Server из C # (или любого языка .NET) заключается в использовании Entity Framework. Преимущество Entity Framework заключается в том, что он обеспечивает более высокий уровень абстракции.

Чтобы цитировать от Microsoft ( https://msdn.microsoft.com/en-us/data/jj590134 ):

Платформа ADO.NET Entity Framework позволяет разработчикам создавать приложения для доступа к данным путем программирования на основе концептуальной модели приложения вместо программирования непосредственно на основе схемы реляционного хранения. Цель состоит в том, чтобы уменьшить объем кода и обслуживания, необходимых для приложений, ориентированных на данные. Приложения Entity Framework предоставляют следующие преимущества:

  • Приложения могут работать с точки зрения более ориентированной на приложения концептуальной модели, включая типы с наследованием, сложные элементы и отношения.
  • Приложения освобождаются от жестко закодированных зависимостей от конкретного механизма обработки данных или схемы хранения.
  • Сопоставления между концептуальной моделью и схемой хранилища могут изменяться без изменения кода приложения.
  • Разработчики могут работать с согласованной объектной моделью приложения, которая может быть сопоставлена ​​с различными схемами хранения, возможно, реализованными в разных системах управления базами данных.
  • Несколько концептуальных моделей могут быть сопоставлены с одной схемой хранения.
  • Поддержка встроенных в язык запросов (LINQ) обеспечивает проверку синтаксиса во время компиляции для запросов по концептуальной модели.

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

«Классический» подход к разработке с использованием SQL Server заключается в размещении логики приложения в хранимых процедурах и программах, которым предоставляются только права безопасности для выполнения хранимых процедур, а не непосредственное обновление таблиц. Концепция здесь заключается в том, что хранимые процедуры являются уровнем бизнес-логики для приложений. Несмотря на то, что теория обоснована, она, как правило, теряет популярность по разным причинам и заменяется реализацией бизнес-логики на языке программирования, таком как C # или VB. Хорошие приложения все еще реализуются с многоуровневым подходом, включая разделение интересов и т. Д., Но с большей вероятностью будут следовать шаблону, подобному MVC.

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

Если, с другой стороны, это делается с помощью ORM, такого как Entity Framework, и в процессе работы обнаруживается, что в редких случаях деньги берут с проверки, но не вкладывают в сбережения, отладка может быть гораздо более сложной, особенно если потенциально задействовано несколько программ. Скорее всего, это будет крайний случай, возможно, связанный со специфическими аппаратными проблемами, которые должны возникать в определенной последовательности и т. Д. Как это проверить?

JonnyBoats
источник
Или другой ОРМ. Их много, с различными преимуществами и недостатками по сравнению с EF.
svick
8
Перечисление недостатков ORM сделало бы этот ответ более полезным.
День
6

На самом деле, основное утверждение является дискуссионным - существуют компромиссы между наличием SQL в коде или кодом в базе данных (куда вы направляетесь с помощью хранимых процедур).

Результатом является то, что не существует единственного «лучшего», это не то, что вы можете обобщить, потому что какой бы путь вы ни пошли, вы идете на компромисс (вы получаете выгоды, но также вводите ограничения).

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

Что важнее, так это беспокоиться об архитектуре и уровне вашего приложения - при наличии соответствующего уровня доступа к данным, будь то использование ORM, такого как Entity Framework или NHibernate или выполнение чего-то более прямого, должно изолировать большую часть вашего приложения от этого решения, независимо от того, создаете ли вы запросы или использовать хранимые процедуры.


Я буду свободно работать над сравнительно небольшими проектами с небольшими командами (1-3 разработчика) - для меня использование хранимых процедур доставляет больше хлопот, чем их ценность, поскольку с учетом характера наших приложений (и моих навыков?) Развертывание новых Код, как правило, намного проще, чем обновление схемы (даже если у меня есть код, который делает обновление схемы относительно простым), и я могу применять бизнес-правила, используя общий код доступа к данным. Это явно классический пример «Ваш пробег может меняться».

Murph
источник
2
+1 для «нет единственного лучшего», -1 для развертывания кода проще, чем развертывание сохраненных изменений процесса, +1 для выбора подхода, который имеет смысл для вашего приложения и обеспечивает изоляцию DAL - так +1.
Джоэл Браун
Я действительно квалифицировал бит развертывания как «для меня», потому что для меня это всегда имело место (особенно для веб-приложений) - несмотря на то, что в этой области это может быть немного переписано.
Murph
+1, что лучше всего зависит от приложения и ситуации.
GrandmasterB
1
Я предполагаю, что это зависит от условий, в которых вы работаете. Если у вас нет администраторов баз данных, которые блокируют вас из производства, перенести сохраненный процесс замены в базу данных может быть пугающе легко. В этом отношении без управления производством перенос новой разметки, сценария и даже нового скомпилированного кода в централизованное приложение также может быть слишком простым.
Джоэл Браун
@JoelBrown - Точно - я полагаю, нет, я уверен, что сделал там целый ряд предположений. Во-первых, моя схема контролируется версией (грубо, но эффективно), я не dba, но я достаточно умен, чтобы понять, что схема должна быть согласованной. Я работаю в основном над веб-приложениями, и вы не можете попасть в базы данных, кроме как на сервер, в то время как я (просто) сократил развертывание приложений до (более или менее) одного нажатия кнопки ... интеграция обновлений схемы в упомянутые развертывание находится в списке, но я всегда находил обновления схемы более напряженными, чем обновления кода (простота отката?)
Murph
4

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

Билл
источник
1
Достаточно ли параметризации? Тебе не нужно продезинфицировать?
StuperUser
это зависит от вашего источника и вашей цели. Я воспринимал его вопрос буквально, он только для чтения с некоторыми параметрами. в обычных случаях худшее, что вы могли бы сделать с грязным вводом при правильной параметризации, это получить исключение типа или без результатов с неверным вводом. Вставка отличается и обычно требует проверки, если вы не считаете источник достоверным.
Билл
0

Здесь передовой опыт действительно преувеличен - есть много хороших способов сделать это, и тот, который вы выберете, должен зависеть от того, что ваше приложение и что вам нужно делать. Тем не менее, есть только две вещи, которые вы можете сделать действительно неправильно:

  • Как указывает @Bill, вы всегда должны параметризировать свои запросы. Построение строк - это простой вектор для внедрения SQL, а также всевозможные трудные для отслеживания ошибок. Гораздо умнее люди придумали, как обучать и избегать SQL, поэтому вам не нужно разбираться в этом самостоятельно.

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

Другой практикой, за которую я бы не согласился, является то, что вы должны сосредоточить свой код доступа к данным в как можно меньшем количестве мест. Мы не разрешаем интерфейсным веб-приложениям хранить прямую ссылку на System.Data.SqlClient, чтобы обеспечить соблюдение этого предостережения.

Уайетт Барнетт
источник