Le SQL en ligne est-il toujours considéré comme une mauvaise pratique maintenant que nous avons des micro ORM?


26

C'est un peu une question ouverte, mais je voulais des opinions, car j'ai grandi dans un monde où les scripts SQL en ligne étaient la norme, puis nous avons tous été très conscients des problèmes liés à l'injection SQL et de la fragilité du SQL quand faire des manipulations de cordes partout.

Puis vint l'aube de l'ORM où vous expliquiez la requête à l'ORM et le laissiez générer son propre SQL, ce qui dans de nombreux cas n'était pas optimal mais était sûr et facile. Une autre bonne chose à propos des ORM ou des couches d'abstraction de base de données était que le SQL a été généré avec son moteur de base de données à l'esprit, donc je pouvais utiliser Hibernate / Nhibernate avec MSSQL, MYSQL et mon code n'a jamais changé, c'était juste un détail de configuration.

Maintenant, passons rapidement à la journée actuelle, où les Micro ORM semblent gagner plus de développeurs.Je me demandais pourquoi nous avions apparemment fait demi-tour sur l'ensemble du sujet SQL en ligne.

Je dois admettre que j'aime l'idée de ne pas avoir de fichiers de configuration ORM et de pouvoir écrire ma requête de manière plus optimale, mais j'ai l'impression de m'ouvrir aux anciennes vulnérabilités telles que l'injection SQL et je m'attache également à un moteur de base de données, donc si je veux que mon logiciel prenne en charge plusieurs moteurs de base de données, je devrais faire un peu plus de piratage de chaînes qui semble alors commencer à rendre le code illisible et plus fragile. (Juste avant que quelqu'un ne le mentionne, je sais que vous pouvez utiliser des arguments basés sur des paramètres avec la plupart des micro orms qui offrent une protection dans la plupart des cas contre l'injection SQL)

Alors, quelles sont les opinions des gens sur ce genre de chose? J'utilise Dapper comme Micro ORM dans ce cas et NHibernate comme ORM normal dans ce scénario, mais la plupart dans chaque domaine sont assez similaires.

Ce que j'appelle sql en ligneest des chaînes SQL dans le code source. Il y avait autrefois des débats sur la conception des chaînes SQL dans le code source, ce qui portait atteinte à l'intention fondamentale de la logique.C'est pourquoi les requêtes de style linq typées de manière statique sont devenues si populaires qu'il ne s'agit que d'un seul langage, mais avec disons C # et Sql sur une seule page, vous avez 2 langues entremêlées dans votre code source brut maintenant. Juste pour clarifier, l'injection SQL n'est qu'un des problèmes connus avec l'utilisation de chaînes sql, je mentionne déjà que vous pouvez empêcher cela de se produire avec des requêtes basées sur des paramètres, mais je souligne d'autres problèmes liés à l'intégration des requêtes SQL dans votre code source, telles que l'absence d'abstraction de fournisseur de base de données ainsi que la perte de tout niveau de capture d'erreur de temps de compilation sur les requêtes basées sur des chaînes, ce sont tous des problèmes que nous avons réussi à contourner avec l'aube des ORM avec leur fonctionnalité de requête de niveau supérieur,

Je suis donc moins concentré sur les problèmes individuels mis en évidence et de plus en plus, il devient maintenant plus acceptable d'avoir à nouveau des chaînes SQL directement dans votre code source, car la plupart des Micro ORM utilisent ce mécanisme.

Voici une question similaire qui a quelques points de vue différents, bien qu'elle concerne davantage le sql en ligne sans le contexte micro orm:

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


1
Pensez-vous que vous pourriez reformuler la question de telle manière qu'elle ne demande pas d'avis? Les sondages d'opinion ne cadrent pas bien avec le format Q&R de Stack Exchange.

Vous pouvez toujours résumer vos requêtes "Micro ORM" dans une classe distincte, où, si nécessaire, vous permutez les requêtes en cours d'exécution lorsque vous modifiez votre SGBD.
CodeCaster

n'ont pas entendu le terme "Micro ORM". voulez-vous dire des ORM qui n'essaient pas de prendre complètement le contrôle de SQL, ou est-ce quelque chose de différent?
Javier

peu importe, après un peu de recherche sur Google, cela semble être une chose .net.
Javier

1
@GrandmasterB: Expliquez pourquoi dans une réponse. J'ai à peu près évité ce problème dans ma réponse, car je pense que c'est une question de compromis.
Robert Harvey

Réponses:


31

Ce que vous décrivez comme "Inline SQL" devrait vraiment être appelé "concaténation de chaînes sans paramétrage", et vous n'avez pas à le faire pour utiliser un Micro ORM en toute sécurité.

Considérez cet exemple Dapper:

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

Il est entièrement paramétré, même si la concaténation de chaînes a lieu. Voir le signe @?

Ou cet exemple:

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

qui est à peu près équivalent au code ADO.NET suivant:

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 });
        }
    }
}

Si vous avez besoin de plus de flexibilité que cela, Dapper fournit des modèles SQL et une AddDynamicParms()fonction. Tous les injections SQL sécurisées.

Alors pourquoi utiliser des chaînes SQL en premier lieu?

Eh bien, pour les mêmes raisons, vous utiliseriez du SQL personnalisé dans n'importe quel autre ORM. L'ORM génère peut-être du code SQL sous-optimal et vous devez l'optimiser. Peut-être que vous voulez faire quelque chose de difficile à faire nativement dans l'ORM, comme les UNION. Ou, vous voulez peut-être simplement éviter la complexité de générer toutes ces classes proxy.

Si vous ne voulez vraiment pas écrire une chaîne SQL pour chaque méthode CRUD dans Dapper (qui le fait?), Vous pouvez utiliser cette bibliothèque:

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

Cela vous permettra d'obtenir un CRUD extrêmement simple et direct, tout en vous offrant la flexibilité des instructions SQL manuscrites. Rappelez-vous, l'exemple ADO.NET ci-dessus était la façon dont tout le monde le faisait avant l'arrivée des ORM; Dapper n'est qu'un mince placage par-dessus.


De bons exemples, j'ai déjà mentionné que vous pouvez contourner l'injection SQL via des paramètres, car ce n'est qu'une partie de la question plus large, ont également ajouté une modification clarifiant ce que je veux dire lorsque j'utilise le terme sql en ligne .
Grofit

J'ai ajouté quelques détails à ma réponse.
Robert Harvey

2
+1 pour plus d'informations sur SimpleCRUD ne savait pas que cela existait.
Grofit

En Java, vous trouverez Mybatis qui est plus léger que Hibernate ou EclipseLink et. Son chemin à parcourir consiste à utiliser des phrases prédéfinies en XML (au lieu de coder en dur sur le code). Il ajoute également des fonctionnalités intéressantes comme conditions préalables pour améliorer le SQL final. Nous avons récemment utilisé un API web avec une concurrence assez élevée et une entreprise pas complexe et cela a très bien fonctionné.
Laiv

2

J'adore sql , et je ne pouvais pas le voir coupé en littéraux de chaîne, j'ai donc écrit une petite extension VS pour vous permettre de travailler avec de vrais fichiers sql dans des projets c #. La modification de SQL dans son propre fichier vous donne Intellisense pour les colonnes et les tables, la validation de la syntaxe, l'exécution des tests, les plans d'exécution et le reste. Lorsque vous enregistrez le fichier, mon extension génère des classes wrapper c #, de sorte que vous n'écrivez jamais une ligne de code de connexion, ou code de commande, ou paramètre ou code de lecteur. Vos requêtes sont toutes paramétrées car il n'y a pas d'autre moyen, et vous avez généré des référentiels et des POCO pour les tests unitaires, avec intellisense pour vos paramètres d'entrée et vos résultats.

Et j'ai jeté des couteaux à steak gratuits ... Quand un expert doit venir retravailler le sql de votre développeur, elle regarde un vrai fichier sql, et n'a pas besoin de toucher un C #. Quand elle revient en arrière et nettoie la base de données, en supprimant certaines colonnes, les références aux colonnes manquantes sautent directement comme des erreurs de compilation dans le c #. La base de données devient exactement comme un autre projet de votre solution que vous pouvez pirater, c'est une interface détectable dans le code. Si la solution se compile, vous savez que toutes vos requêtes fonctionnent. Il n'y a aucune erreur d'exécution due à des transtypages non valides, à des noms de colonnes non valides ou à des requêtes non valides.

En repensant à Dapper, que nous utilisons toujours au travail, je ne peux pas croire qu'en 2016, c'est la chose la plus cool en matière d'accès aux données. La génération de msil à l'exécution est intelligente, mais toutes les erreurs sont des erreurs d'exécution et la manipulation de chaînes, comme la manipulation de chaînes à d'autres fins, prend du temps, est fragile et sujette aux erreurs. Et comment peut-il être sec d'avoir à répéter les noms de vos colonnes dans votre POCO, que vous devez écrire et maintenir à la main.

Alors voilà. Si vous voulez regarder une technologie d'accès aux données inconnue d'un développeur inconnu travaillant dans ses temps libres (avec un jeune enfant et beaucoup d'autres passe-temps), c'est ici .


Vous semblez penser beaucoup à votre petite "innovation", mais en quoi est-ce différent de, disons, ExecuteStoreQuery ou ExecuteStoreCommand dans Entity Framework?
Robert Harvey

Je n'entre pas dans le débat EF ou SQL. Mon truc est pour les gens qui veulent utiliser SQL. Donc, comme moyen d'exécuter SQL, ExecuteStoreQuery () remplira vos POCO pour vous, mais vous avez encore besoin de définir vos POCO, par l'apparence des choses? Et cela ne vous aide pas à mettre le sql dans un fichier ou à créer vos paramètres. Votre requête n'est ni détectable dans le code, ni testable. La suppression de colonnes ne produira pas d'erreurs de compilation dans votre application. Je pourrais continuer, mais je crains de me répéter :-) Peut-être pourriez-vous prendre 3 minutes pour regarder la vidéo youtube. C'est en français, baissez le son! Anglais à venir.
bbsimonbb

EF est tout à fait capable de générer automatiquement tous les POCO. Qu'est-ce que j'oublie ici? La véritable innovation de Dapper et Massive est que vous n'avez pas du tout besoin de POCO; vous pouvez simplement utiliser dynamic.
Robert Harvey

Je ne sais presque rien d'EF. ExecuteStoreQuery () remplira une entité. Va-t-il générer une entité à partir de la requête . Les entités sont générées à partir d'objets DB (ou vice versa), pas à partir de requêtes. Si votre requête ne correspond pas à une entité existante, vous devez écrire votre POCO, non?
bbsimonbb

1
:-) je dois dire que je suis sensible aux accusations de publicité lorsque je mets ma meilleure idée en liberté. Voici mon dernier morceau de commercialisme agressif. Au bout de 3 minutes, vous devriez savoir si je suis sur quelque chose ou non.
bbsimonbb

1

Les requêtes paramétrées ainsi que le modèle de conception du référentiel vous donnent un contrôle total sur ce qui est inclus dans la requête pour empêcher les attaques par injection. Inline SQL dans ce cas n'est pas un problème autre que la lisibilité pour les requêtes volumineuses et complexes, qui devraient de toute façon être dans les procédures stockées.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.