Meilleure pratique pour interroger les données de MS SQL Server en C #?

9

Quelle est la meilleure façon d'interroger des données à partir d'un serveur MS SQL en C #?

Je sais que ce n'est pas une bonne pratique d'avoir une requête SQL dans le code.

Est le meilleur moyen de créer une procédure stockée et de l'appeler à partir de C # avec des paramètres?

using (var conn = new SqlConnection(connStr))
using (var command = new SqlCommand("StoredProc", conn) { CommandType = CommandType.StoredProcedure }) {
   conn.Open();
   command.ExecuteNonQuery();
   conn.Close();
}
Bruno
la source
8
"Je sais que ce n'est pas une bonne pratique d'avoir une requête SQL dans le code." - imo, c'est absurde.
GrandmasterB
4
Vous n'avez pas besoin d'appeler conn.Close () si vous l'avez créé dans un bloc using. L'intérêt du bloc using est d'imiter le style C ++ de nettoyage du destructeur. Un nettoyage élégant d'un âge plus civilisé. Pas aussi aléatoire ou maladroit que le style try-catch.
Lord Tydus
2
Pour info. Les procédures stockées sont également du «code». L'intérêt des procs stockés était de permettre le mélange du code procédural avec le style SQL basé sur un ensemble. Vous aurez donc une requête dans le code malgré tout. Pour les applications à volume extrêmement élevé, il est parfois préférable d'avoir une logique exécutée en dehors de la base de données pour permettre une mise à l'échelle horizontale en ajoutant des serveurs. Si vous pouvez gérer une seule base de données, mais un multi-serveur pour la logique, la mise à l'échelle devient beaucoup plus facile.
Lord Tydus
@GrandmasterB nous avons une quantité substantielle de SQL inline en C # (notre C # LOC est maintenant près de 2 millions) - et 6 ans plus tard, il revient pour nous mordre parce que nous devons maintenant traquer ce SQL inline (nous avons récemment embauché un expert SQL - nous faisons donc des réglages de performances). Faites-moi confiance: vous ne savez jamais à quel point votre application deviendra importante et comment les choses changeront à l'avenir. Conservez différentes langues dans différents fichiers, même si vous les déléguez simplement aux ressources manifestes. Vous pouvez aussi le // SQLCODEfaire - mais vous devez vous souvenir de le faire.
Jonathan Dickinson
1
@JonathanDickinson, utilisez des proc stockés si vous le souhaitez. J'ai dit à plusieurs reprises qu'ils sont utiles lorsque vous avez des bases de code disparates fonctionnant avec la même base de données. Mais juste parce qu'ils sont utiles dans certaines circonstances, cela ne fait pas automatiquement de ne pas les utiliser en permanence . Si l'utilisation directe d'instructions SQL ne cause pas de problème, ce n'est pas une «mauvaise pratique» pour cette application.
GrandmasterB

Réponses:

10

L'utilisation de procédures stockées est un moyen et est largement utilisé depuis de nombreuses années.

Une façon plus moderne d'interagir avec les bases de données SQL Server à partir de C # (ou de tout langage .NET) consiste à utiliser Entity Framework. L'avantage d'Entity Framework est qu'il fournit un niveau d'abstraction plus élevé.

Pour citer Microsoft ( https://msdn.microsoft.com/en-us/data/jj590134 ):

ADO.NET Entity Framework permet aux développeurs de créer des applications d'accès aux données en programmant avec un modèle d'application conceptuel au lieu de programmer directement avec un schéma de stockage relationnel. L'objectif est de réduire la quantité de code et de maintenance requise pour les applications orientées données. Les applications Entity Framework offrent les avantages suivants:

  • Les applications peuvent fonctionner en termes d'un modèle conceptuel plus axé sur les applications, y compris les types avec héritage, les membres complexes et les relations.
  • Les applications sont libérées des dépendances codées en dur sur un moteur de données ou un schéma de stockage particulier.
  • Les mappages entre le modèle conceptuel et le schéma spécifique au stockage peuvent changer sans changer le code d'application.
  • Les développeurs peuvent travailler avec un modèle objet d'application cohérent qui peut être mappé à différents schémas de stockage, éventuellement implémentés dans différents systèmes de gestion de base de données.
  • Plusieurs modèles conceptuels peuvent être mappés sur un seul schéma de stockage.
  • La prise en charge des requêtes intégrées au langage (LINQ) fournit une validation de la syntaxe au moment de la compilation pour les requêtes par rapport à un modèle conceptuel.

L'utilisation d'un ORM vs procédures stockées implique des compromis, en particulier en termes de sécurité et où réside la logique.

L'approche «classique» du développement avec SQL Server consiste à faire en sorte que la logique d'application réside dans les procédures stockées et les programmes uniquement dotés de droits de sécurité pour exécuter les procédures stockées, et non pour mettre à jour les tables directement. Le concept ici est que les procédures stockées sont la couche de logique métier pour les applications. Bien que la théorie soit solide, elle a eu tendance à tomber en disgrâce pour diverses raisons, étant remplacée par la mise en œuvre de la logique métier dans un langage de programmation comme C # ou VB. Les bonnes applications sont toujours mises en œuvre avec une approche à plusieurs niveaux, y compris la séparation des préoccupations, etc., mais sont plus susceptibles de suivre un modèle comme MVC.

Un inconvénient de l'implémentation de la logique dans l'ORM plutôt que dans la base de données est la facilité de débogage et de test des règles d'intégrité des données par les responsables de la base de données (DA ou DBA). Prenons l'exemple classique du transfert d'argent de votre chèque vers votre compte d'épargne, il est important que cela se fasse comme une unité de travail atomique, en d'autres termes pris en sandwich dans une transaction. Si ce type de transfert n'est autorisé que par le biais d'une procédure stockée, il est relativement facile pour le DA et les auditeurs de contrôler la qualité de la procédure stockée.

Si, d'autre part, cela se fait via un ORM comme Entity Framework et en production, on découvre que, dans de rares occasions, l'argent est retiré de la vérification mais non investi dans le débogage des économies peut être beaucoup plus complexe, en particulier si plusieurs programmes sont potentiellement impliqués. Ce serait très probablement un cas de bord, impliquant peut-être des problèmes matériels particuliers qui doivent se produire dans une séquence particulière, etc. Comment peut-on tester cela?

JonnyBoats
la source
Ou tout autre ORM. Il y en a beaucoup, avec divers avantages et inconvénients par rapport à EF.
svick
8
L'énumération des inconvénients des ORM rendrait cette réponse plus utile.
Den
6

En fait, l'affirmation de base est discutable - il y a des compromis dans les deux sens entre avoir SQL dans le code ou avoir du code dans la base de données (c'est là que vous vous dirigez avec les procédures stockées).

Le résultat est qu'il n'y a pas de "meilleur" unique, ce n'est pas quelque chose que vous pouvez généraliser car quelle que soit la façon dont vous allez, vous faites un compromis (vous gagnez des avantages mais introduisez également des contraintes).

S'il existe une correspondance un à un entre votre application et votre base de données, cela n'a pas vraiment d'importance. Si, en revanche, vous disposez d'une grande base de données principale partagée par un nombre important d'applications, l'application de la cohérence au sein de la base de données entre ces applications devient beaucoup plus importante.

Ce qui est plus important, c'est de s'inquiéter de l'architecture et de la superposition de votre application - étant donné une couche d'accès aux données appropriée, que l'utilisation d'un ORM comme Entity Framework ou NHibernate ou faire quelque chose de plus direct devrait isoler la majeure partie de votre application de cette décision, que vous construisiez ou non des requêtes ou utiliser des procédures stockées.


Je serai libre d'avoir tendance à travailler sur des projets relativement petits avec de petites équipes (1 à 3 développeurs) - l'utilisation de procédures stockées est, pour moi, plus difficile que sa valeur car étant donné la nature de nos applications (et mes compétences?) Déployant de nouvelles le code est généralement beaucoup plus facile que la mise à jour du schéma (même si je dispose d'un code qui rend la mise à jour du schéma relativement simple) et je suis en mesure d'appliquer des règles métier en utilisant un code d'accès aux données commun. Il s'agit clairement d'un exemple classique de "Votre kilométrage peut varier".

Murph
la source
2
+1 pour "pas le meilleur", -1 pour déployer du code est plus facile que de déployer des modifications de proc stockées, +1 pour choisir une approche qui a du sens pour votre application et assure l'isolement DAL - So +1.
Joel Brown
J'ai qualifié le bit de déploiement avec "pour moi" parce que cela a toujours été le cas pour moi (en particulier pour les applications Web) - pour autant que cela puisse supporter un peu de réécriture dans ce domaine.
Murph
+1, ce qui dépend le mieux de l'application et de la situation.
GrandmasterB
1
Je suppose que cela dépend des conditions dans lesquelles vous travaillez. Si vous n'avez pas de DBA vous bloquant la production, il peut être extrêmement facile de supprimer un proc stocké de remplacement dans la base de données. D'ailleurs, sans que les contrôles de production ne suppriment un nouveau balisage, un script et même un nouveau code compilé dans une application centralisée peut également être beaucoup trop facile.
Joel Brown
@JoelBrown - Exactement - je suppose que non, je suis certain d'avoir fait tout un tas d'hypothèses là-bas. Premièrement, mon schéma est contrôlé par version (de manière grossière mais efficace), je ne suis pas dba mais je suis assez intelligent pour savoir que son schéma doit être cohérent. Je travaille principalement sur des applications Web et vous ne pouvez pas accéder aux bases de données sauf en visitant le serveur, alors que j'ai (juste) réduit le déploiement d'applications à (plus ou moins) un seul clic de bouton ... intégrant les mises à jour du schéma dans ledit le déploiement est sur la liste, mais j'ai toujours trouvé les mises à jour de schéma plus stressantes que les mises à jour de code (facilité de restauration?)
Murph
4

Tant que vous avez paramétré vos entrées, toute approche est valide. La plupart des requêtes ne contenant pas d'arguments de code sont venues du mauvais vieux temps où de nombreuses bibliothèques vous ont forcé à ajouter vos instructions ensemble et c'est de là que proviennent les attaques par injection sql.

Facture
la source
1
Le paramétrage est-il suffisant? Vous n'avez pas besoin de désinfecter également?
StuperUser
cela dépend de votre source et de votre objectif. Je prenais sa question à la lettre, il est en lecture seule avec quelques paramètres. dans les cas courants, le pire que vous feriez avec une entrée sale si elle est correctement paramétrée est d'obtenir une exception de type ou aucun résultat avec une mauvaise entrée. L'insertion est différente et nécessite généralement une validation, sauf si vous traitez la source comme faisant autorité.
Bill
0

Les meilleures pratiques sont vraiment exagérées ici - il existe de nombreuses bonnes façons de le faire et celle que vous choisissez doit vraiment dépendre de ce qu'est votre application et de ce que vous devez faire. Cela dit, il n'y a que deux choses que vous pouvez vraiment faire de mal:

  • Comme le souligne @Bill, vous devez toujours paramétrer vos requêtes. La construction de chaînes est un vecteur facile pour l'injection SQL ainsi que toutes sortes de bogues difficiles à localiser. Des gens beaucoup plus intelligents ont compris comment tupéliser et échapper sql afin que vous n'ayez pas besoin de le découvrir vous-même.

  • Fermez vos connexions. La meilleure façon est de tout envelopper une instruction using, mais essayez / catch / enfin est cool aussi si cela fait flotter votre bateau. Mais assurez-vous toujours d'utiliser une connexion comme une voiture bon marché - conduisez-la durement et rapidement et supprimez-la rapidement.

L'autre pratique pour laquelle je plaiderais avec véhémence est que vous devez vous assurer de concentrer votre code d'accès aux données dans le moins d'endroits possible. Nous n'autorisons pas les applications Web frontales à contenir une référence directe à System.Data.SqlClient pour aider à appliquer cette mise en garde.

Wyatt Barnett
la source