Wird Inline-SQL nach wie vor als schlechte Praxis eingestuft, da wir über Micro-ORMs verfügen?

26

Dies ist ein bisschen eine offene Frage, aber ich wollte ein paar Meinungen, da ich in einer Welt aufgewachsen bin, in der Inline-SQL-Skripte die Norm waren. Dann wurden wir alle auf SQL-Injection-basierte Probleme aufmerksam gemacht und wie zerbrechlich der SQL-Code war, wenn überall Saitenmanipulationen durchführen.

Dann kam der Beginn des ORM, in dem Sie dem ORM die Abfrage erklärten und es sein eigenes SQL generieren ließen, was in vielen Fällen nicht optimal, aber sicher und einfach war. Ein weiterer Vorteil von ORMs oder Datenbankabstraktionsebenen war, dass SQL mit Blick auf die Datenbank-Engine generiert wurde, sodass ich Hibernate / Nhibernate mit MSSQL, MYSQL verwenden konnte und mein Code nie geändert wurde, sondern nur ein Konfigurationsdetail war.

Jetzt geht es schnell zum aktuellen Tag, an dem Micro-ORMs mehr Entwickler zu überzeugen scheinen. Ich habe mich gefragt, warum wir anscheinend eine Kehrtwende in Bezug auf das gesamte Inline-SQL-Thema vollzogen haben.

Ich muss zugeben, ich mag die Idee, keine ORM-Konfigurationsdateien zu haben und in der Lage zu sein, meine Abfrage optimaler zu schreiben, aber es fühlt sich an, als würde ich mich wieder den alten Schwachstellen wie SQL Injection öffnen und mich auch daran binden Eine Datenbank-Engine. Wenn meine Software mehrere Datenbank-Engines unterstützen soll, müsste ich mehr String-Hacker-Aktionen ausführen, die den Code unleserlicher und anfälliger machen. (Kurz bevor jemand es erwähnt, weiß ich, dass Sie parameterbasierte Argumente mit den meisten Mikroorganismen verwenden können, was in den meisten Fällen Schutz vor SQL-Injektionen bietet.)

Also, was sind die Meinungen der Menschen über diese Art von Dingen? In diesem Fall verwende ich Dapper als Mikro-ORM und NHibernate als reguläres ORM. Die meisten in den einzelnen Bereichen sind jedoch ziemlich ähnlich.

Was ich als Inline-SQL bezeichneist SQL-Zeichenfolgen im Quellcode. Früher gab es Designdebatten über SQL-Zeichenfolgen im Quellcode, die die grundlegende Intention der Logik beeinträchtigten, weshalb statisch typisierte Abfragen im Linq-Stil so populär wurden, dass es immer noch nur eine Sprache gibt, aber mit C # und Sql auf einer Seite 2 Sprachen vermischen sich jetzt in Ihrem rohen Quellcode. Zur Verdeutlichung: Die SQL-Injection ist nur eines der bekannten Probleme bei der Verwendung von SQL-Strings. Ich erwähne bereits, dass Sie dies bei parameterbasierten Abfragen verhindern können. Ich möchte jedoch auf andere Probleme hinweisen, bei denen SQL-Abfragen in Ihrem Quellcode verankert sind, z Das Fehlen der DB Vendor-Abstraktion sowie der Verlust jeglicher Kompilierzeitfehler bei der Erfassung von Zeichenfolgen-basierten Abfragen sind alles Probleme, die wir mit der Entstehung von ORMs mit ihrer höheren Abfragefunktionalität umgehen konnten.

Daher konzentriere ich mich weniger auf die einzelnen hervorgehobenen Probleme, und vor allem wird es jetzt akzeptabler, SQL-Zeichenfolgen wieder direkt in Ihrem Quellcode zu haben, da die meisten Micro-ORMs diesen Mechanismus verwenden.

Hier ist eine ähnliche Frage, die einige unterschiedliche Gesichtspunkte hat, obwohl es mehr um den Inline-SQL ohne den Mikro-Orm-Kontext geht:

https://stackoverflow.com/questions/5303746/is-inline-sql-hard-coding

Grofit
quelle
1
Glaubst du, du könntest die Frage so umformulieren, dass sie keine Meinung erfordert? Meinungsumfragen passen nicht gut zum Q & A-Format von Stack Exchange.
Sie können Ihre "Micro ORM" -Abfragen jederzeit in einer separaten Klasse abstrahieren. Bei Bedarf tauschen Sie die ausgeführten Abfragen aus, wenn Sie Ihr DBMS ändern.
CodeCaster
habe den Begriff "Micro ORM" nicht gehört. Meinen Sie ORMs, die nicht versuchen, SQL vollständig zu übernehmen, oder ist das etwas anderes?
Javier
vergiss nicht, nach ein wenig googeln scheint es eine .net sache zu sein.
Javier
1
@GrandmasterB: Erkläre in einer Antwort, warum. Ich bin dieser Frage in meiner Antwort ziemlich aus dem Weg gegangen, da ich glaube, dass es eine Frage der Kompromisse ist.
Robert Harvey

Antworten:

31

Was Sie als "Inline SQL" bezeichnen, sollte eigentlich als "Zeichenkettenverkettung ohne Parametrisierung" bezeichnet werden, und Sie müssen dies nicht tun, um ein Micro ORM sicher zu verwenden.

Betrachten Sie dieses Dapper-Beispiel:

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

Es ist vollständig parametrisiert, obwohl die Verkettung von Zeichenfolgen stattfindet. Sehen Sie das @ -Zeichen?

Oder dieses Beispiel:

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

Dies entspricht in etwa dem folgenden ADO.NET-Code:

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

Wenn Sie mehr Flexibilität benötigen, bietet Dapper SQL-Vorlagen und eine AddDynamicParms()Funktion. Alle SQL Injection sicher.

Warum also überhaupt SQL-Strings verwenden?

Nun, aus den gleichen Gründen würden Sie benutzerdefiniertes SQL in jedem anderen ORM verwenden. Möglicherweise ist das ORM ein Code-generierendes suboptimales SQL und Sie müssen es optimieren. Vielleicht möchten Sie etwas tun, das im ORM von Haus aus schwierig zu tun ist, wie z. B. UNIONs. Oder Sie möchten einfach die Komplexität der Generierung all dieser Proxy-Klassen vermeiden.

Wenn Sie wirklich keine SQL-Zeichenfolge für jede CRUD- Methode in Dapper schreiben möchten (wer tut das?), Können Sie diese Bibliothek verwenden:

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

Dadurch erhalten Sie eine äußerst einfache und unkomplizierte CRUD, während Sie gleichzeitig die Flexibilität handgeschriebener SQL-Anweisungen erhalten. Denken Sie daran, dass das obige ADO.NET-Beispiel so war, wie es alle vor der Einführung von ORMs gemacht haben. Dapper ist nur ein dünnes Furnier darüber.

Robert Harvey
quelle
Gute Beispiele, ich habe bereits erwähnt, dass Sie die SQL-Injection über Parameter umgehen können, da dies nur ein Teil der größeren Frage ist. Außerdem wurde eine Bearbeitung hinzugefügt, die klarstellt, was ich meine, wenn ich den Begriff Inline-SQL verwende .
Grofit
Ich habe meiner Antwort einige Details hinzugefügt.
Robert Harvey
2
+1 für Informationen über SimpleCRUD wusste nicht, dass dies existiert.
Grofit
In Java finden Sie Mybatis, das leichter ist als Hibernate oder EclipseLink und. Der Weg dorthin führt über vordefinierte Sätze in XML (anstatt Code hart zu codieren). Außerdem werden einige interessante Funktionen als Voraussetzungen für die Verbesserung des endgültigen SQL hinzugefügt. Wir haben kürzlich ein API-Web verwendet, das eine ziemlich hohe Nebenläufigkeit und ein nicht komplexes Geschäft aufweist, und es hat großartig funktioniert.
Laiv
2

Ich liebe SQL und konnte es nicht ertragen, es in String-Literale zerlegt zu sehen. Deshalb habe ich eine kleine VS-Erweiterung geschrieben, mit der Sie mit echten SQL-Dateien in C # -Projekten arbeiten können. Wenn Sie sql in einer eigenen Datei bearbeiten, erhalten Sie Informationen zu Spalten und Tabellen, zur Syntaxüberprüfung, zur Testausführung, zu Ausführungsplänen und zum Rest. Wenn Sie die Datei speichern, generiert meine Erweiterung C # -Wrapperklassen, sodass Sie niemals eine Zeile mit Verbindungscode, Befehlscode, Parametercode oder Lesercode schreiben. Ihre Abfragen sind alle parametrisiert, da es keine andere Möglichkeit gibt und Sie Repositorys und POCOs für Unit-Tests generiert haben, mit Intellisense für Ihre Eingabeparameter und Ihre Ergebnisse.

Und ich habe kostenlose Steakmesser reingeworfen ... Wenn eine Expertin die SQL Ihres Entwicklers überarbeiten muss, schaut sie sich eine echte SQL-Datei an und muss kein C # berühren. Wenn sie zurückgeht und die Datenbank aufräumt und einige Spalten löscht, springen Verweise auf fehlende Spalten direkt als Kompilierungsfehler in c # heraus. Die Datenbank wird genau wie ein anderes Projekt in Ihrer Lösung, in das Sie sich hacken können. Sie ist als Schnittstelle im Code erkennbar. Wenn die Lösung kompiliert wird, wissen Sie, dass alle Ihre Abfragen funktionieren. Es gibt keine Laufzeitfehler aufgrund ungültiger Besetzungen oder ungültiger Spaltennamen oder ungültiger Abfragen.

Rückblickend auf dapper, das wir immer noch bei der Arbeit verwenden, kann ich nicht glauben, dass dies 2016 die coolste Sache beim Datenzugriff ist. Die Laufzeit-Msil-Generierung ist in jedem Fall clever, aber alle Fehler sind Laufzeitfehler, und die Manipulation von Zeichenfolgen wie auch die Manipulation von Zeichenfolgen für andere Zwecke ist zeitaufwändig, zerbrechlich und fehleranfällig. Und wie kann es trocken sein, Ihre Spaltennamen in Ihrem POCO wiederholen zu müssen, die Sie von Hand schreiben und pflegen müssen.

Hier bitteschön. Wenn Sie sich eine unbekannte Datenzugriffstechnologie eines unerhörten Entwicklers ansehen möchten, der in seiner Freizeit arbeitet (mit einem kleinen Kind und vielen anderen Hobbys), dann ist sie hier vorbei .

bbsimonbb
quelle
Sie denken anscheinend viel über Ihre kleine "Innovation" nach, aber wie unterscheidet sich dies beispielsweise von ExecuteStoreQuery oder ExecuteStoreCommand in Entity Framework?
Robert Harvey
Ich komme nicht in die EF- oder SQL-Debatte. Mein Ding ist für Leute, die SQL benutzen wollen. Um SQL auszuführen, füllt ExecuteStoreQuery () Ihre POCOs für Sie, aber Sie müssen noch Ihre POCOs nach dem Aussehen der Dinge definieren? Und es hilft Ihnen nicht, die SQL in eine Datei einzufügen oder Ihre Parameter zu erstellen. Ihre Abfrage ist weder im Code erkennbar noch testbar. Das Löschen von Spalten führt nicht zu Kompilierungsfehlern in Ihrer Anwendung. Ich könnte weitermachen, aber ich fürchte, ich wiederhole mich :-) Vielleicht könntest du 3 Minuten brauchen, um das YouTube-Video anzusehen. Es ist auf Französisch, leiser! Englisch kommt.
BBSimonbb
EF ist durchaus in der Lage, alle POCOs automatisch zu generieren. Was vermisse ich hier? Die wirkliche Innovation von Dapper and Massive ist, dass Sie POCOs überhaupt nicht benötigen. Sie können nur verwenden dynamic.
Robert Harvey
Ich weiß fast nichts über EF. ExecuteStoreQuery () füllt eine Entität. Erzeugt es eine Entität aus der Abfrage . Entitäten werden aus DB-Objekten (oder umgekehrt) generiert, nicht aus Abfragen. Wenn Ihre Abfrage nicht mit einer vorhandenen Entität übereinstimmt, müssen Sie Ihr POCO schreiben, nicht wahr?
bbsimonbb
1
:-) muss sagen, ich werde empfindlich gegenüber Werbekosten, wenn ich meine beste Idee frei zur Verfügung stelle. Hier ist mein neuster aggressiver Kommerz. An der 3-Minuten-Marke sollten Sie wissen, ob ich auf etwas stehe oder nicht.
bbsimonbb
1

Parametrisierte Abfragen sowie das Repository-Entwurfsmuster geben Ihnen die volle Kontrolle darüber, was in die Abfrage eingeht, um Injection-Angriffe zu verhindern. Inline-SQL ist in diesem Fall kein anderes Problem als die Lesbarkeit für große und komplexe Abfragen, die sich sowieso in gespeicherten Prozeduren befinden sollten.

Kyle JV
quelle