Wird es als Anti-Pattern angesehen, SQL in eine Anwendung wie diese fest zu codieren:
public List<int> getPersonIDs()
{
List<int> listPersonIDs = new List<int>();
using (SqlConnection connection = new SqlConnection(
ConfigurationManager.ConnectionStrings["Connection"].ConnectionString))
using (SqlCommand command = new SqlCommand())
{
command.CommandText = "select id from Person";
command.Connection = connection;
connection.Open();
SqlDataReader datareader = command.ExecuteReader();
while (datareader.Read())
{
listPersonIDs.Add(Convert.ToInt32(datareader["ID"]));
}
}
return listPersonIDs;
}
Normalerweise hätte ich eine Repository-Ebene usw., aber ich habe sie der Einfachheit halber im obigen Code ausgeschlossen.
Ich hatte kürzlich ein Feedback von einem Kollegen, der sich beschwerte, dass SQL im Quellcode geschrieben wurde. Ich hatte keine Chance zu fragen warum und er ist jetzt für zwei Wochen weg (vielleicht mehr). Ich nehme an, er meinte entweder:
- Verwenden Sie LINQ
oder - Verwenden Sie gespeicherte Prozeduren für SQL
Hab ich recht? Wird es als Anti-Pattern angesehen, SQL in den Quellcode zu schreiben? Wir sind ein kleines Team, das an diesem Projekt arbeitet. Der Vorteil von Stored Procedures besteht meines Erachtens darin, dass SQL-Entwickler in den Entwicklungsprozess einbezogen werden können (Schreiben von Stored Procedures usw.).
Bearbeiten Der folgende Link behandelt fest codierte SQL-Anweisungen: https://docs.microsoft.com/en-us/sql/odbc/reference/develop-app/hard-coded-sql-statements . Hat es einen Vorteil, eine SQL-Anweisung zu erstellen?
Antworten:
Sie haben den entscheidenden Teil der Einfachheit halber ausgeschlossen. Das Repository ist die Abstraktionsschicht für die Persistenz. Wir unterteilen die Persistenz in eine eigene Ebene, damit wir die Persistenztechnologie bei Bedarf einfacher ändern können . Wenn SQL also außerhalb der Persistenzschicht liegt, wird der Aufwand für eine separate Persistenzschicht vollständig zunichte gemacht.
Als Ergebnis: SQL ist in der Persistenzschicht, die für eine SQL-Technologie spezifisch ist, in Ordnung (z. B. SQL ist in a
SQLCustomerRepository
in Ordnung, aber nicht in aMongoCustomerRepository
). Außerhalb der Persistenzschicht unterbricht SQL Ihre Abstraktion und wird daher (von mir) als sehr schlechte Praxis angesehen .Zu Tools wie LINQ oder JPQL: Diese können lediglich die SQL-Varianten abstrahieren. Wenn LINQ-Code- oder JPQL-Abfragen außerhalb eines Repositorys vorhanden sind, wird die Persistenzabstraktion genauso unterbrochen wie bei unformatiertem SQL.
Ein weiterer großer Vorteil einer separaten Persistenzschicht besteht darin, dass Sie Ihren Geschäftslogikcode auflösen können, ohne einen DB-Server einrichten zu müssen.
Sie erhalten schnelle Unit-Tests mit geringem Speicherprofil und reproduzierbaren Ergebnissen auf allen Plattformen, die Ihre Sprache unterstützt.
In einer MVC + Service-Architektur ist dies eine einfache Aufgabe, die Repository-Instanz zu verspotten, einige Versuchsdaten im Speicher zu erstellen und zu definieren, dass das Repository diese Versuchsdaten zurückgeben soll, wenn ein bestimmter Getter aufgerufen wird. Sie können dann Testdaten pro Unittest definieren und müssen sich anschließend keine Gedanken mehr über das Aufräumen der Datenbank machen.
Das Testen von Schreibvorgängen in die Datenbank ist ebenso einfach: Stellen Sie sicher, dass die relevanten Aktualisierungsmethoden auf der Persistenzschicht aufgerufen wurden, und bestätigen Sie, dass sich die Entitäten zu diesem Zeitpunkt im richtigen Zustand befanden.
quelle
Die meisten Standard-Geschäftsanwendungen verwenden heutzutage unterschiedliche Ebenen mit unterschiedlichen Verantwortlichkeiten. Jedoch welche Schichten die Sie für Ihre Anwendung, und die Schicht , die Verantwortung an Ihnen und Ihrem Team ist. Bevor Sie eine Entscheidung treffen können, ob es richtig oder falsch ist, SQL direkt in die Funktion zu setzen, die Sie uns gezeigt haben, müssen Sie wissen
Welche Ebene in Ihrer Anwendung hat welche Verantwortung
Aus welcher Schicht stammt die obige Funktion?
Hierfür gibt es keine "Einheitslösung". In einigen Anwendungen bevorzugen die Designer die Verwendung eines ORM-Frameworks und lassen das Framework alle SQL-Anweisungen generieren. In einigen Anwendungen ziehen es die Designer vor, solche SQL-Anweisungen ausschließlich in gespeicherten Prozeduren zu speichern. Für einige Anwendungen gibt es eine handgeschriebene Persistenz- (oder Repository-) Schicht, in der sich das SQL befindet, und für andere Anwendungen ist es in Ordnung, unter bestimmten Umständen Ausnahmen zu definieren, um SQL strikt in dieser Persistenzschicht zu platzieren.
Also, worüber müssen Sie nachdenken: Welche Schichten möchten oder benötigen Sie in Ihrer speziellen Anwendung und wie möchten Sie die Zuständigkeiten? Sie haben geschrieben: "Normalerweise hätte ich eine Repository-Ebene" , aber welche genauen Verantwortlichkeiten möchten Sie in dieser Ebene haben und welche Verantwortlichkeiten möchten Sie an eine andere Stelle legen? Beantworten Sie dies zuerst, dann können Sie Ihre Frage selbst beantworten.
quelle
Marstato gibt eine gute Antwort, aber ich möchte noch einen Kommentar hinzufügen.
SQL in Source ist KEIN Anti-Pattern, kann aber Probleme verursachen. Ich kann mich erinnern, wann Sie SQL-Abfragen in die Eigenschaften von Komponenten stellen mussten, die auf jedes Formular abgelegt wurden. Das machte die Dinge sehr schnell hässlich und man musste durch die Reifen springen, um Abfragen zu finden. Ich bin ein starker Befürworter der Zentralisierung des Datenbankzugriffs innerhalb der Grenzen der Sprachen, mit denen ich gearbeitet habe, geworden. Ihr Kollege kann Rückblenden zu diesen dunklen Tagen erhalten.
In einigen Kommentaren geht es jetzt um die Lieferantenbindung, als wäre dies automatisch eine schlechte Sache. Ist es nicht. Wenn ich jedes Jahr einen sechsstelligen Scheck unterzeichne, um Oracle zu verwenden, können Sie wetten, dass jede Anwendung, die auf diese Datenbank zugreift, die zusätzliche Oracle-Syntax entsprechend verwenden sollaber in vollen Zügen. Ich werde nicht glücklich sein, wenn meine glänzende Datenbank von Programmierern, die Vanille-ANSI-SQL schlecht schreiben, verkrüppelt wird, wenn es eine "Oracle-Methode" zum Schreiben von SQL gibt, die die Datenbank nicht verkrüppelt. Ja, das Ändern von Datenbanken wird schwieriger sein, aber ich habe es in über 20 Jahren nur ein paarmal bei einem großen Kunden gesehen, und einer dieser Fälle ging von DB2 -> Oracle über, weil der Mainframe, auf dem DB2 gehostet wurde, veraltet war und außer Betrieb genommen wurde . Ja, das ist eine Lieferantenbindung, aber für Unternehmenskunden ist es wünschenswert, für ein teures, leistungsfähiges RDBMS wie Oracle oder Microsoft SQL Server zu zahlen und es dann in vollem Umfang zu nutzen. Sie haben eine Supportvereinbarung als Ihre Komfortdecke. Wenn ich für eine Datenbank mit einer umfangreichen Implementierung gespeicherter Prozeduren zahle,
Dies führt zum nächsten Punkt: Wenn Sie eine Anwendung schreiben, die auf eine SQL-Datenbank zugreift , müssen Sie SQL sowie die andere Sprache lernen, und mit lernen meine ich auch die Abfrageoptimierung. Ich werde mich über Sie ärgern, wenn Sie SQL-Generierungscode schreiben, der den SQL-Cache mit einer Flut nahezu identischer Abfragen spült, wenn Sie eine geschickt parametrisierte Abfrage hätten verwenden können.
Keine Ausreden, kein Versteck hinter einer Mauer aus Winterschlaf. ORMs schlecht kann verwendet wirklich die Leistung von Anwendungen lahmlegen. Ich erinnere mich, dass ich vor ein paar Jahren eine Frage zu Stack Overflow gesehen habe:
Wie wäre es mit "UPDATE table SET field1 = wobei field2 True und Field3> 100 ist". Das Erstellen und Entsorgen von 250.000 Objekten könnte Ihr Problem sein ...
dh Ruhezustand ignorieren, wenn es nicht angebracht ist, ihn zu verwenden. Verstehen Sie die Datenbank.
Zusammenfassend lässt sich sagen, dass das Einbetten von SQL in Code eine schlechte Praxis sein kann, aber es gibt viel schlimmere Dinge, die Sie tun können, wenn Sie versuchen, das Einbetten von SQL zu vermeiden.
quelle
Ja, das feste Codieren von SQL-Zeichenfolgen in Anwendungscode ist im Allgemeinen ein Anti-Pattern.
Lassen Sie uns versuchen, die Toleranz, die wir aus jahrelanger Sicht im Produktionscode entwickelt haben, aufzuheben. Das Mischen völlig unterschiedlicher Sprachen mit unterschiedlicher Syntax in derselben Datei ist im Allgemeinen keine wünschenswerte Entwicklungstechnik. Dies unterscheidet sich von Vorlagensprachen wie Razor, die so konzipiert sind, dass sie mehreren Sprachen eine kontextbezogene Bedeutung verleihen. Wie Sava B. in einem Kommentar unten erwähnt, ist SQL in C # oder einer anderen Anwendungssprache (Python, C ++ usw.) eine Zeichenfolge wie jede andere und semantisch bedeutungslos. Dasselbe gilt in den meisten Fällen für das Mischen mehrerer Sprachen, obwohl dies offensichtlich in bestimmten Situationen akzeptabel ist, z. B. Inline-Assemblierung in C, kleine und verständliche CSS-Ausschnitte in HTML (wobei darauf hingewiesen wird, dass CSS für das Mischen mit HTML ausgelegt ist) ), und andere.
(Robert C. Martin über das Mischen von Sprachen, Clean Code , Kapitel 17, "Code Smells and Heuristics", Seite 288)
Für diese Antwort werde ich mich auf SQL konzentrieren (wie in der Frage gestellt). Die folgenden Probleme können auftreten, wenn SQL als ein Satz nicht zugeordneter Zeichenfolgen à la carte gespeichert wird:
@
Präfix von C # erleichtert dies, aber ich habe viel Code gesehen, der jede SQL-Zeile in Anführungszeichen setzt und die Zeilenumbrüche übergeht."SELECT col1, col2...colN"\ "FROM painfulExample"\ "WHERE maintainability IS NULL"\ "AND modification.effort > @necessary"\
Vollständige ORMs (Object-Relational Mappers wie Entity Framework oder Hibernate) können zufällig gepfeffertes SQL im Anwendungscode eliminieren. Meine Verwendung von SQL- und Ressourcendateien ist nur ein Beispiel. ORMs, Hilfsklassen usw. können dazu beitragen, das Ziel eines saubereren Codes zu erreichen.
Wie Kevin in einer früheren Antwort sagte, kann SQL in Code in kleinen Projekten akzeptabel sein, aber große Projekte beginnen als kleine Projekte, und die Wahrscheinlichkeit, dass die meisten Teams zurückkehren und es richtig machen, ist oft umgekehrt proportional zur Codegröße.
Es gibt viele einfache Möglichkeiten, SQL in einem Projekt beizubehalten. Eine der Methoden, die ich häufig verwende, besteht darin, jede SQL-Anweisung in eine Visual Studio-Ressourcendatei mit dem Namen "sql" zu schreiben. Eine Textdatei, ein JSON-Dokument oder eine andere Datenquelle kann abhängig von Ihren Tools sinnvoll sein. In einigen Fällen ist eine separate Klasse für die Erstellung von SQL-Zeichenfolgen möglicherweise die beste Option, kann jedoch einige der oben beschriebenen Probleme aufweisen.
SQL-Beispiel: Was sieht eleganter aus ?:
Wird
Der SQL-Code befindet sich immer in einer leicht zu lokalisierenden Datei oder in einer Gruppe von Dateien, von denen jede einen beschreibenden Namen hat, der beschreibt, was sie tun, anstatt wie sie es tun :
Diese einfache Methode führt eine Einzelabfrage aus. Meiner Erfahrung nach steigt der Nutzen, wenn die Verwendung der "Fremdsprache" komplexer wird. Meine Verwendung einer Ressourcendatei ist nur ein Beispiel. Je nach Sprache (in diesem Fall SQL) und Plattform können unterschiedliche Methoden geeigneter sein.
Diese und andere Methoden lösen die obige Liste folgendermaßen auf:
SQL
.return SqlResource.DoTheThing;
Diese Implementierungen können zwar die Ressource überspringen und die SQL in einer Zeichenfolge enthalten, es treten jedoch weiterhin einige (nicht alle) der oben genannten Probleme auf.sql.GetOrdersForAccount
anstatt stumpferSELECT ... FROM ... WHERE...
Die Erstellung von SQL in einer Ressource ist schnell, sodass die Vermischung der Ressourcennutzung mit SQL-in-Code kaum einen Anreiz bietet.
Unabhängig von der gewählten Methode habe ich festgestellt, dass das Mischen von Sprachen normalerweise die Codequalität verringert. Ich hoffe, dass einige der hier beschriebenen Probleme und Lösungen Entwicklern helfen, diesen Codegeruch zu beseitigen, wenn dies angebracht ist.
quelle
Es hängt davon ab, ob. Es gibt verschiedene Ansätze, die funktionieren können:
Wenn Ihr Projekt bereits eine dieser Techniken gewählt hat, sollten Sie, wie es häufig der Fall ist, mit dem Rest des Projekts konsistent sein.
(1) und (3) sind beide relativ gut darin, die Unabhängigkeit zwischen der Anwendungslogik und der Datenbank aufrechtzuerhalten, da die Anwendung weiterhin grundlegende Rauchtests kompiliert und durchführt, wenn Sie die Datenbank durch einen anderen Anbieter ersetzen. Die meisten Anbieter entsprechen jedoch nicht vollständig dem SQL-Standard. Das Ersetzen eines Anbieters durch einen anderen Anbieter erfordert daher wahrscheinlich umfangreiche Tests und die Suche nach Fehlern, unabhängig davon, welche Technik Sie verwenden. Ich bin skeptisch, dass dies eine so große Sache ist, wie die Leute es sich vorstellen. Das Ändern von Datenbanken ist im Grunde ein letzter Ausweg, wenn Sie die aktuelle Datenbank nicht entsprechend Ihren Anforderungen abrufen können. In diesem Fall haben Sie die Datenbank wahrscheinlich schlecht ausgewählt.
Die Wahl zwischen (1) und (3) hängt hauptsächlich davon ab, wie sehr Sie ORMs mögen. Meiner Meinung nach werden sie überbeansprucht. Sie sind eine schlechte Darstellung des relationalen Datenmodells, da Zeilen keine Identität haben, wie Objekte Identität haben. Es ist wahrscheinlich, dass Sie auf Schmerzpunkte in Bezug auf eindeutige Einschränkungen und Verknüpfungen stoßen, und Sie haben möglicherweise Schwierigkeiten, einige kompliziertere Abfragen zu formulieren, abhängig von der Leistungsfähigkeit des ORM. Andererseits wird (1) wahrscheinlich wesentlich mehr Code erfordern als ein ORM.
(2) ist meiner Erfahrung nach selten zu sehen. Das Problem ist, dass viele Shops SWEs verbieten, das Datenbankschema direkt zu ändern (weil "das der Job des DBAs ist"). Dies ist nicht unbedingt eine schlechte Sache an sich; Schemaänderungen bergen ein erhebliches Potenzial, Dinge zu beschädigen, und müssen möglicherweise sorgfältig umgesetzt werden. Damit jedoch (2) funktioniert, sollten SWEs zumindest in der Lage sein, neue Ansichten einzuführen und die Hintergrundabfragen bestehender Ansichten mit minimalem oder unbürokratischem Aufwand zu ändern. Wenn dies an Ihrem Arbeitsplatz nicht der Fall ist, wird (2) wahrscheinlich nicht für Sie arbeiten.
Wenn Sie dagegen (2) zum Laufen bringen können, ist es viel besser als die meisten anderen Lösungen, da die relationale Logik in SQL anstelle von Anwendungscode beibehalten wird. Im Gegensatz zu Allzweck-Programmiersprachen ist SQL speziell für das relationale Datenmodell konzipiert und kann dementsprechend komplizierte Datenabfragen und -transformationen besser ausdrücken. Sichten können auch zusammen mit dem Rest Ihres Schemas portiert werden, wenn Sie Datenbanken ändern, aber dies erschwert das Verschieben.
Für Lesezugriffe sind gespeicherte Prozeduren im Grunde genommen nur eine schlechtere Version von (2). Ich empfehle sie in dieser Eigenschaft nicht, aber Sie möchten sie möglicherweise trotzdem zum Schreiben, wenn Ihre Datenbank keine aktualisierbaren Ansichten unterstützt oder wenn Sie etwas Komplexeres tun müssen, als jeweils eine einzelne Zeile einzufügen oder zu aktualisieren (z. B. Transaktionen, Lesen-Schreiben usw.). Sie können Ihre gespeicherte Prozedur mithilfe eines Triggers mit einer Ansicht koppeln (d. H
CREATE TRIGGER trigger_name INSTEAD OF INSERT ON view_name FOR EACH ROW EXECUTE PROCEDURE procedure_name;
), aber es gibt erhebliche Meinungsverschiedenheiten darüber, ob dies tatsächlich eine gute Idee ist. Befürworter werden Ihnen mitteilen, dass die SQL-Anweisungen, die Ihre Anwendung ausführt, so einfach wie möglich sind. Kritiker werden Ihnen sagen, dass dies ein inakzeptables Maß an "Magie" ist und dass Sie die Prozedur einfach direkt aus Ihrer Anwendung heraus ausführen sollten. Ich würde sagen , dass dies eine bessere Idee , wenn Ihre gespeicherte Prozedur aussieht oder viel wie ein wirktINSERT
,UPDATE
oderDELETE
, und eine schlechtere Idee , wenn es etwas anderes tut. Letztendlich musst du selbst entscheiden, welcher Stil sinnvoller ist.(4) ist die Nichtlösung. Es kann sich für kleine oder große Projekte lohnen, die nur sporadisch mit der Datenbank interagieren. Bei Projekten mit viel SQL ist dies jedoch keine gute Idee, da möglicherweise Duplikate oder Variationen derselben Abfrage in der Anwendung zufällig verteilt sind, was die Lesbarkeit und das Refactoring beeinträchtigt.
quelle
Nicht unbedingt. Wenn Sie alle Kommentare hier lesen, finden Sie im Quellcode gültige Argumente für die Hardcodierung von SQL-Anweisungen.
Das Problem liegt darin, wo Sie die Anweisungen platzieren . Wenn Sie die SQL-Anweisungen überall im Projekt platzieren, werden Sie wahrscheinlich einige der SOLID-Prinzipien ignorieren, nach denen wir normalerweise streben.
Wir können nicht sagen, was er meinte. Wir können es jedoch erraten. Zum Beispiel ist das erste, was mir einfällt, die Lieferantenbindung . Das Hardcodieren von SQL-Anweisungen kann dazu führen, dass Sie Ihre Anwendung eng mit der DB-Engine koppeln. Verwenden Sie beispielsweise bestimmte Funktionen des Herstellers, die nicht ANSI-kompatibel sind.
Das ist nicht unbedingt falsch oder schlecht. Ich zeige nur auf die Tatsache.
Das Ignorieren von SOLID-Grundsätzen und Herstellersperren hat möglicherweise nachteilige Folgen, die Sie möglicherweise ignorieren. Deshalb ist es normalerweise gut, mit dem Team zusammenzusitzen und seine Zweifel zu entlarven.
Ich denke, es hat nichts mit den Vorteilen gespeicherter Prozeduren zu tun. Wenn Ihr Kollege hartkodiertes SQL nicht mag, wird ihn wahrscheinlich auch die Verlagerung des Geschäfts auf gespeicherte Prozeduren nicht mögen.
Ja. Die Post listet die Vorteile vorbereiteter Aussagen auf . Es ist eine Art SQL-Template. Sicherer als die Verkettung von Zeichenfolgen. Aber der Beitrag ermutigt Sie nicht, diesen Weg zu gehen und bestätigt Ihnen nicht, dass Sie Recht haben. Es wird nur erklärt, wie wir fest codiertes SQL auf sichere und effiziente Weise verwenden können.
Fragen Sie zunächst Ihren Kollegen. Senden Sie eine Mail, rufen Sie ihn an, ... Ob er antwortet oder nicht, setzen Sie sich zum Team und entlarven Sie Ihre Zweifel. Finden Sie die Lösung, die Ihren Anforderungen am besten entspricht. Machen Sie keine falschen Annahmen basierend auf dem, was Sie dort lesen.
quelle
select GETDATE(), ....
GETDATE () ist die Datumsfunktion von SqlServer. In anderen Enginees hat die Funktion einen anderen Namen, einen anderen Ausdruck, ...Ich denke, es ist eine schlechte Praxis, ja. Andere haben auf die Vorteile hingewiesen, den gesamten Datenzugriffscode in einer eigenen Schicht zu speichern. Sie müssen nicht danach suchen, es ist einfacher zu optimieren und zu testen ... Aber auch innerhalb dieser Ebene haben Sie einige Möglichkeiten: Verwenden Sie ein ORM, verwenden Sie Sprocs oder betten Sie SQL-Abfragen als Zeichenfolgen ein. Ich würde sagen, SQL-Abfragezeichenfolgen sind bei weitem die schlechteste Option.
Mit einem ORM wird die Entwicklung viel einfacher und weniger fehleranfällig. Mit EF definieren Sie Ihr Schema, indem Sie einfach Ihre Modellklassen erstellen (Sie hätten diese Klassen ohnehin erstellen müssen). Das Abfragen mit LINQ ist ein Kinderspiel - Sie kommen oft mit 2 Zeilen c # davon, wo Sie sonst einen Sproc schreiben und warten müssten. Meiner Meinung nach hat dies einen enormen Vorteil in Bezug auf Produktivität und Wartbarkeit - weniger Code, weniger Probleme. Aber es gibt einen Performance-Overhead, selbst wenn Sie wissen, was Sie tun.
Sprocs (oder Funktionen) sind die andere Option. Hier schreiben Sie Ihre SQL-Abfragen manuell. Aber zumindest bekommt man eine Garantie dafür, dass sie korrekt sind. Wenn Sie in .NET arbeiten, wird Visual Studio sogar Compilerfehler auslösen, wenn die SQL ungültig ist. Das ist toll. Wenn Sie eine Spalte ändern oder entfernen und einige Ihrer Abfragen ungültig werden, werden Sie dies wahrscheinlich während der Kompilierungszeit herausfinden. Es ist auch viel einfacher, Sprocs in ihren eigenen Dateien zu verwalten - wahrscheinlich erhalten Sie Syntaxhervorhebung, automatische Vervollständigung usw.
Wenn Ihre Abfragen als Sprocs gespeichert sind, können Sie sie auch ändern, ohne die Anwendung erneut zu kompilieren und bereitzustellen. Wenn Sie feststellen, dass etwas in Ihrem SQL-Code nicht funktioniert, kann ein DBA es einfach beheben, ohne auf Ihren App-Code zugreifen zu müssen. Wenn Ihre Abfragen aus String-Literalen bestehen, können Sie dbas im Allgemeinen nicht annähernd so einfach ausführen.
SQL-Abfragen als Zeichenfolgenliterale machen den C # -Code für den Datenzugriff auch weniger lesbar.
Nur als Faustregel sind magische Konstanten schlecht. Das schließt Zeichenkettenliterale ein.
quelle
Es ist kein Anti-Muster (diese Antwort ist gefährlich nah an der Meinung). Die Code-Formatierung ist jedoch wichtig, und die SQL-Zeichenfolge sollte so formatiert sein, dass sie sich deutlich vom Code unterscheidet, der sie verwendet. Zum Beispiel
quelle
Ich kann Ihnen nicht sagen, was Ihr Kollege gemeint hat. Aber ich kann das beantworten:
JA . Die Verwendung von vorbereiteten Anweisungen mit gebundenen Variablen ist die empfohlene Abwehr gegen SQL-Injection , das seit über einem Jahrzehnt das größte Sicherheitsrisiko für Webanwendungen darstellt . Dieser Angriff ist so verbreitet, dass er vor fast zehn Jahren in Web-Comics vorgestellt wurde, und es ist höchste Zeit, effektive Abwehrmechanismen einzusetzen.
... und die wirksamste Abwehr gegen eine fehlerhafte Verkettung von Abfragezeichenfolgen besteht darin, Abfragen nicht in erster Linie als Zeichenfolgen darzustellen, sondern eine typsichere Abfrage-API zum Erstellen von Abfragen zu verwenden. So würde ich beispielsweise Ihre Abfrage in Java mit QueryDSL schreiben:
Wie Sie sehen, gibt es hier kein einziges Zeichenfolgenliteral, wodurch eine SQL-Injection nahezu unmöglich wird. Außerdem wurde der Code beim Schreiben vervollständigt, und meine IDE kann ihn umgestalten, falls ich die ID-Spalte jemals umbenennen möchte. Außerdem kann ich leicht alle Abfragen für die Personentabelle finden, indem ich meine IDE frage, wo auf die
person
Variable zugegriffen wird. Oh, und haben Sie bemerkt, dass es viel kürzer und augenschonender ist als Ihr Code?Ich kann nur davon ausgehen, dass so etwas auch für C # verfügbar ist. Zum Beispiel höre ich großartige Dinge über LINQ.
Zusammenfassend lässt sich sagen, dass die Darstellung von Abfragen als SQL-Zeichenfolgen es der IDE erschwert, das Schreiben und Umgestalten von Abfragen sinnvoll zu unterstützen, die Erkennung von Syntax- und Typfehlern von der Kompilierungszeit bis zur Laufzeit verzögert und eine Ursache für SQL-Injection-Schwachstellen darstellt [1]. Es gibt also gute Gründe, warum man SQL-Strings im Quellcode nicht haben möchte.
[1]: Ja, die korrekte Verwendung von vorbereiteten Anweisungen verhindert auch die SQL-Injection. Aber dass eine andere Antwort in diesem Thread für eine SQL-Injection anfällig war, bis ein Kommentator darauf hinwies, weckt kein Vertrauen, dass Junior-Programmierer sie bei Bedarf korrekt verwenden ...
quelle
Viele tolle Antworten hier. Abgesehen von dem, was bereits gesagt wurde, möchte ich noch etwas hinzufügen.
Ich betrachte die Verwendung von Inline-SQL nicht als Antimuster. Was ich jedoch für ein Anti-Pattern halte, ist, dass jeder Programmierer sein eigenes Ding macht. Sie müssen sich als Team für einen gemeinsamen Standard entscheiden. Wenn alle Benutzer linq verwenden, verwenden Sie linq. Wenn alle Benutzer Ansichten und gespeicherte Prozeduren verwenden, tun Sie dies.
Sei aber immer aufgeschlossen und verlass dich nicht auf Dogmas. Wenn es sich bei Ihrem Shop um einen "Linq" -Shop handelt, verwenden Sie diesen. Abgesehen von diesem einen Ort, an dem Linq absolut nicht funktioniert. (Aber Sie sollten nicht 99,9% der Zeit.)
Ich würde also den Code in der Codebasis recherchieren und herausfinden, wie Ihre Kollegen arbeiten.
quelle
Der Code sieht aus wie aus der datenbankinteragierenden Schicht, die sich zwischen der Datenbank und dem Rest des Codes befindet. Wenn ja, ist dies kein Anti-Pattern.
Diese Methode ist der Teil der Schicht, auch wenn OP anders denkt (einfacher Datenbankzugriff, keine Vermischung mit etwas anderem). Es ist vielleicht nur schlecht im Code platziert. Diese Methode gehört zur separaten Klasse "Datenbankschnittstellenebene". Es wäre ein Anti-Pattern, es in der normalen Klasse neben den Methoden zu platzieren, die Nicht-Datenbankaktivitäten implementieren.
Das Anti-Pattern wäre, SQL von einem anderen zufälligen Ort des Codes aufzurufen. Sie müssen eine Ebene zwischen der Datenbank und dem Rest des Codes definieren, aber es ist nicht so, dass Sie unbedingt ein beliebtes Tool verwenden müssen, das Ihnen dabei helfen könnte.
quelle
Meiner Meinung nach ist no kein Antimuster, aber Sie werden sich mit dem Zeichenfolgenformatierungsabstand befassen, insbesondere bei großen Abfragen, die nicht in eine Zeile passen.
Ein weiterer Vorteil ist, dass es bei dynamischen Abfragen, die unter bestimmten Bedingungen erstellt werden sollten, viel schwieriger wird.
Ich schlage vor, einen SQL-Abfrage-Generator zu verwenden
quelle
Für viele moderne Organisationen mit schnellen Implementierungs-Pipelines, in denen Codeänderungen innerhalb von Minuten kompiliert, getestet und in die Produktion übertragen werden können, ist es absolut sinnvoll, SQL-Anweisungen in den Anwendungscode einzubetten. Dies ist nicht unbedingt ein Anti-Muster, je nachdem, wie Sie vorgehen.
Ein gültiger Fall für die Verwendung gespeicherter Prozeduren ist heutzutage in Organisationen, in denen es um Produktionsbereitstellungen viel Prozess gibt, der Wochen mit QA-Zyklen usw. umfassen kann. In diesem Szenario kann das DBA-Team Leistungsprobleme beheben, die erst nach der anfänglichen Produktionsbereitstellung auftreten, indem es optimiert die Abfragen in den gespeicherten Prozeduren.
Sofern Sie nicht in dieser Situation sind, empfehle ich, dass Sie Ihre SQL in Ihren Anwendungscode einbetten. Lesen Sie andere Antworten in diesem Thread, um Ratschläge zu erhalten, wie Sie am besten vorgehen können.
Originaltext unten für den Kontext
Der Hauptvorteil von Stored Procedures besteht darin, dass Sie die Datenbankleistung optimieren können, ohne Ihre Anwendung neu kompilieren und erneut bereitstellen zu müssen.
In vielen Organisationen kann Code erst nach einem QS-Zyklus usw., der Tage oder Wochen dauern kann, in die Produktion verschoben werden. Wenn auf Ihrem System ein Problem mit der Datenbankleistung auftritt, weil sich das Verwendungsmuster ändert oder die Tabellengröße usw. zunimmt, kann es schwierig sein, das Problem mit fest codierten Abfragen aufzuspüren, während die Datenbank über Tools / Berichte usw. verfügt, mit denen fehlerhafte gespeicherte Prozeduren identifiziert werden . Mit gespeicherten Prozeduren können Lösungen in der Produktion getestet / bewertet und das Problem schnell behoben werden, ohne dass eine neue Version der Anwendungssoftware installiert werden muss.
Wenn dieses Problem in Ihrem System nicht wichtig ist, ist es eine absolut gültige Entscheidung, SQL-Anweisungen fest in die Anwendung zu codieren.
quelle