Wird es als Anti-Pattern angesehen, SQL in den Quellcode zu schreiben?


87

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:

  1. Verwenden Sie LINQ
    oder
  2. 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?


31
"Use Linq" und "Use Stored Procedures" sind keine Gründe; Sie sind nur Vorschläge. Warten Sie zwei Wochen und fragen Sie ihn nach Gründen.
Robert Harvey

47
Das Stack Exchange-Netzwerk verwendet ein Mikro-ORM namens Dapper. Ich denke, es ist vernünftig zu sagen, dass die überwiegende Mehrheit des Dapper-Codes "hardcoded SQL" ist (mehr oder weniger). Wenn es sich also um eine schlechte Praxis handelt, dann handelt es sich um eine schlechte Praxis, die von einer der bekanntesten Webanwendungen der Welt übernommen wurde.
Robert Harvey

16
Bei der Beantwortung Ihrer Frage zu Repositorys handelt es sich bei fest codiertem SQL immer noch um fest codiertes SQL, unabhängig davon, wo Sie es ablegen. Der Unterschied besteht darin, dass das Repository Ihnen einen Platz bietet, an dem Sie das fest codierte SQL einkapseln können . Es ist eine Abstraktionsebene, die die Details der SQL vor dem Rest des Programms verbirgt.
Robert Harvey

26
Nein, SQL im Code ist kein Anti-Pattern. Aber das ist eine Menge Code für eine einfache SQL-Abfrage.
GroßmeisterB

45
Es gibt einen Unterschied zwischen "im Quellcode" und "über den gesamten Quellcode verteilt"
bis

Antworten:


112

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 SQLCustomerRepositoryin Ordnung, aber nicht in a MongoCustomerRepository). 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.


80
Die Idee, dass "wir die Persistenztechnologie ändern können", ist in den allermeisten realen Projekten unrealistisch und unnötig. Eine SQL / relationale DB ist eine völlig andere Bestie als NoSQL-DBs wie MongoDB. Siehe dazu diesen ausführlichen Artikel . Allenfalls würde ein Projekt, das mit der Verwendung von NoSQL begann, irgendwann seinen Fehler bemerken und dann zu einem RDBMS wechseln. Nach meiner Erfahrung erzielen Sie die besten Ergebnisse, wenn Sie die direkte Verwendung einer objektorientierten Abfragesprache (wie JPA-QL) aus Geschäftscode zulassen.
Rogério

6
Was ist, wenn die Wahrscheinlichkeit sehr gering ist, dass sich die Persistenzschicht ändert? Was ist, wenn es beim Ändern der Persistenzschicht keine Eins-zu-Eins-Zuordnung gibt? Was ist der Vorteil der zusätzlichen Abstraktionsebene?
Bitte

19
@ Rogério Die Migration von einem NoSQL-Speicher zu einem RDBMS oder umgekehrt ist, wie Sie sagen, wahrscheinlich nicht realistisch (vorausgesetzt, die Wahl der Technologie war anfangs angemessen). Ich war jedoch an einer Reihe von Projekten in der Praxis beteiligt, bei denen wir von einem RDBMS auf ein anderes migriert haben. In diesem Szenario ist eine gekapselte Persistenzschicht definitiv ein Vorteil.
David

6
"Die Idee, dass" wir die Persistenztechnologie ändern können ", ist in den allermeisten Projekten der realen Welt unrealistisch und unnötig." Mein Unternehmen hat zuvor Code unter dieser Annahme geschrieben. Wir mussten die gesamte Codebasis überarbeiten, um nicht nur ein, sondern drei völlig unterschiedliche Speicher- / Abfragesysteme zu unterstützen, und erwägen ein drittes und ein viertes. Schlimmer noch, selbst wenn wir nur eine Datenbank hatten, führte der Mangel an Konsolidierung zu allen Arten von Codesünden.
NPSF3000,

3
@ Rogerio Du kennst die "große Mehrheit der realen Projekte"? In meinem Unternehmen können die meisten Anwendungen mit einem von vielen gängigen DBMS arbeiten, und dies ist sehr nützlich, da die meisten unserer Kunden diesbezüglich nicht funktionierende Anforderungen haben.
BartoszKP

55

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.


1
Ich habe die Frage bearbeitet. Ich bin mir nicht sicher, ob es Licht verbreitet.
w0051977

18
@ w0051977: Der Link, den Sie gepostet haben, sagt nichts über Ihre Bewerbung aus, oder? Anscheinend suchen Sie nach einer einfachen Braindead-Regel, um SQL zu platzieren, oder nicht, die für jede Anwendung geeignet ist. Da ist gar nichts. Dies ist eine Designentscheidung, die Sie über Ihre individuelle Bewerbung treffen müssen (wahrscheinlich zusammen mit Ihrem Team).
Doc Brown

7
+1. Insbesondere würde ich bemerken, dass es keinen wirklichen Unterschied zwischen SQL in einer Methode und SQL in einer gespeicherten Prozedur gibt, in Bezug darauf, wie "hartcodiert" etwas ist oder wie wiederverwendbar, wartbar usw. Jede Abstraktion, die Sie mit a machen können Verfahren kann mit einer Methode durchgeführt werden. Natürlich können Prozeduren nützlich sein, aber eine rote Regel "Wir können SQL in Methoden nicht haben, also lassen Sie uns alles in Prozeduren setzen" wird wahrscheinlich nur eine Menge Cruft mit wenig Nutzen produzieren.

1
@ user82096 Ich würde allgemein sagen, dass das Einfügen von DB-Zugangscode in SPs in fast jedem Projekt, das ich gesehen habe, nachteilig war. (MS-Stack) Abgesehen von tatsächlichen Leistungseinbußen (starren Ausführungsplan-Caches) wurde die Wartung des Systems durch die Aufteilung der Logik und die Wartung der SPs durch eine andere Gruppe von Personen als die Entwickler der App-Logik erschwert. Insbesondere in Azure, wo Codeänderungen zwischen Bereitstellungsslots wie Sekundenarbeit sind, sind nicht-Code-First- / DB-First-Schema-Migrationen zwischen Slots jedoch ein Problem für den Betrieb.
Sentinel

33

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:

Im Ruhezustand werden 250.000 Datensätze durchlaufen, um die Werte einiger Eigenschaften zu überprüfen und Objekte zu aktualisieren, die bestimmten Bedingungen entsprechen. Es läuft ein bisschen langsam, was kann ich tun, um es zu beschleunigen?

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.


5
Ich habe nicht angegeben, dass "Vendor Lock-In" eine schlechte Sache ist. Ich sagte, es kommt mit Kompromissen. Auf dem heutigen Markt mit db as xaaS werden solche alten Verträge und Lizenzen für den Betrieb von Selfhosted-Datenbanken immer seltener. Es ist heute viel einfacher, die Datenbank von Anbieter A auf B zu ändern, verglichen mit dem Stand vor 10 Jahren. Wenn Sie die Kommentare lesen, bin ich nicht dafür, alle Funktionen des Datenspeichers zu nutzen. So ist es einfach, bestimmte Herstellerangaben in eine App zu schreiben, die herstellerunabhängig ist. Wir sind bestrebt, SOLiD bis zum Ende zu folgen und den Code auf einen einzigen Datenspeicher zu beschränken. Keine große Sache
Laiv

2
Das ist eine großartige Antwort. Oft ist der richtige Ansatz derjenige, der zu der am wenigsten schlechten Situation führt, wenn der schlechtestmögliche Code geschrieben wird. Der schlechteste ORM-Code ist möglicherweise viel schlechter als der schlechteste Embedded SQL-Code.
JWG

@Laiv gute Punkte PaaS ist ein bisschen wie ein Game Changer - ich muss mehr über die Auswirkungen nachdenken.
Mcottle

3
@jwg Ich würde gerne sagen, dass überdurchschnittlicher ORM-Code schlechter ist als unterdurchschnittliches Embedded SQL :)
mcottle

@macottle Unter der Annahme, dass der unterdurchschnittliche Embedded SQL-Wert von ppl über dem Durchschnitt desjenigen geschrieben wurde, der einen ORM geschrieben hat. Was ich bezweifle Es sehr. Viele Entwickler sind nicht in der Lage, Left-JOINs zu schreiben, ohne SO zuerst auszuchecken.
Laiv,

14

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.

Clean Code von Robert C. Martin, pg.  288 (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:

  • Die Datenbanklogik ist schwer zu finden. Wonach suchen Sie, um alle Ihre SQL-Anweisungen zu finden? Zeichenfolgen mit "SELECT", "UPDATE", "MERGE" usw.?
  • Das Refactoring von Anwendungen mit demselben oder ähnlichem SQL wird schwierig.
  • Das Hinzufügen von Unterstützung für andere Datenbanken ist schwierig. Wie würde man das erreichen? Fügen Sie if..then-Anweisungen für jede Datenbank hinzu und speichern Sie alle Abfragen als Zeichenfolgen in der Methode.
  • Entwickler lesen eine Anweisung in einer anderen Sprache und werden durch die Verschiebung des Fokus vom Zweck der Methode zu den Implementierungsdetails der Methode (wie und woher Daten abgerufen werden) abgelenkt.
  • Während Einzeiler kein allzu großes Problem darstellen, fallen Inline-SQL-Zeichenfolgen auseinander, wenn Anweisungen komplexer werden. Was machen Sie mit einer 113-Zeilen-Anweisung? Setzen Sie alle 113 Zeilen in Ihre Methode ein?
  • Wie verschiebt der Entwickler Abfragen effizient zwischen seinem SQL-Editor (SSMS, SQL Developer usw.) und seinem Quellcode hin und her? Das @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"\
  • Einrückungszeichen, die zum Ausrichten der SQL an den umgebenden Anwendungscode verwendet werden, werden bei jeder Ausführung über das Netzwerk übertragen. Dies ist für kleine Anwendungen wahrscheinlich unbedeutend, kann sich jedoch mit zunehmender Nutzung der Software summieren.

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 ?:

using(DbConnection connection = Database.SystemConnection()) {
    var eyesoreSql = @"
    SELECT
        Viewable.ViewId,
        Viewable.HelpText,
        PageSize.Width,
        PageSize.Height,
        Layout.CSSClass,
        PaginationType.GroupingText
    FROM Viewable
    LEFT JOIN PageSize
        ON PageSize.Id = Viewable.PageSizeId
    LEFT JOIN Layout
        ON Layout.Id = Viewable.LayoutId
    LEFT JOIN Theme
        ON Theme.Id = Viewable.ThemeId
    LEFT JOIN PaginationType
        ON PaginationType.Id = Viewable.PaginationTypeId
    LEFT JOIN PaginationMenu
        ON PaginationMenu.Id = Viewable.PaginationMenuId
    WHERE Viewable.Id = @Id
    ";
    var results = connection.Query<int>(eyesoreSql, new { Id });
}

Wird

using(DbConnection connection = Database.SystemConnection()) {
    var results = connection.Query<int>(sql.GetViewable, new { Id });
}

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 :

SQL in einer Ressource

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:

  1. Der Datenbankcode ist leicht zu finden, da er bereits zentralisiert ist. In größeren Projekten gruppieren Sie like-SQL in separaten Dateien, möglicherweise unter einem Ordner mit dem Namen SQL.
  2. Die Unterstützung für eine zweite, dritte usw. Datenbank ist einfacher. Erstellen Sie eine Schnittstelle (oder eine andere Sprachabstraktion), die die eindeutigen Anweisungen jeder Datenbank zurückgibt. Die Implementierung für jede Datenbank besteht nur aus Anweisungen, die den folgenden ähneln: 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.
  3. Refactoring ist einfach - verwenden Sie einfach dieselbe Ressource erneut. Mit wenigen Formatanweisungen können Sie sogar häufig denselben Ressourceneintrag für verschiedene DBMS-Systeme verwenden. Ich mache das oft.
  4. Die Verwendung der Sekundärsprache kann beschreibende Namen verwenden, z. B. sql.GetOrdersForAccountanstatt stumpferSELECT ... FROM ... WHERE...
  5. SQL-Anweisungen werden unabhängig von ihrer Größe und Komplexität mit einer Zeile aufgerufen.
  6. SQL kann zwischen Datenbank-Tools wie SSMS und SQL Developer kopiert und eingefügt werden, ohne dass Änderungen oder sorgfältiges Kopieren erforderlich sind. Keine Anführungszeichen. Keine nachgestellten Backslashes. Im Fall des Visual Studio-Ressourceneditors wird durch einen Klick die SQL-Anweisung hervorgehoben. STRG + C und dann in den SQL-Editor einfügen.

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.


13
Ich denke, das konzentriert sich viel zu sehr auf eine schlechte Kritik daran, SQL im Quellcode zu haben. Es ist nicht unbedingt furchtbar, zwei verschiedene Sprachen in derselben Datei zu haben. Es hängt von vielen Dingen ab, wie sie zusammenhängen und wie sie jeweils dargestellt werden.
Freitag,

9
"Mischen völlig unterschiedlicher Sprachen mit unterschiedlicher Syntax in derselben Datei" Dies ist ein schreckliches Argument. Dies gilt auch für die Razor-Ansichts-Engine sowie für HTML, CSS und Javascript. Liebe deine Graphic Novels!
Ian Newson

4
Dies verschiebt die Komplexität nur an einen anderen Ort. Ja, Ihr ursprünglicher Code ist sauberer, und der Entwickler muss zu Wartungszwecken eine indirekte Verknüpfung hinzufügen, zu der er jetzt navigieren muss. Der eigentliche Grund dafür ist, dass jede SQL-Anweisung an mehreren Stellen im Code verwendet wird. Auf diese Weise unterscheidet es sich wirklich nicht von jedem anderen gewöhnlichen Refactoring ("Extraktionsmethode").
Robert Harvey

3
Um es klarer zu machen: Dies ist keine Antwort auf die Frage "Was mache ich mit meinen SQL-Strings?", Sondern vielmehr eine Antwort auf die Frage "Was mache ich mit einer Sammlung von ausreichend komplexen Strings?" Ihre Antwort beredte Adressen.
Robert Harvey

2
@RobertHarvey: Ich bin mir sicher, dass unsere Erfahrungen unterschiedlich sind, aber ich selbst habe festgestellt, dass die fragliche Abstraktion in den meisten Fällen ein Gewinn ist. Ich werde mit Sicherheit meine Abstraktionskompromisse verfeinern, wie ich es jahrelang getan habe, und werde vielleicht eines Tages SQL wieder in den Code einbauen. YMMV. :) Ich denke, Microservices können großartig sein, und sie trennen im Allgemeinen Ihre SQL-Details (wenn SQL überhaupt verwendet wird) vom Kernanwendungscode. Ich befürworte weniger "verwende meine spezifische Methode: Ressourcen" als vielmehr "Mische im Allgemeinen keine Öl- und Wassersprachen".
Charles Burns

13

Es hängt davon ab, ob. Es gibt verschiedene Ansätze, die funktionieren können:

  1. Modularisieren Sie die SQL und isolieren Sie sie in eine separate Gruppe von Klassen, Funktionen oder in die von Ihrem Paradigma verwendete Abstraktionseinheit. Rufen Sie sie dann mit der Anwendungslogik auf.
  2. Verschieben Sie alle komplexen SQL-Anweisungen in Ansichten und führen Sie dann nur sehr einfache SQL-Anweisungen in der Anwendungslogik aus, damit Sie nichts modularisieren müssen.
  3. Verwenden Sie eine objektrelationale Zuordnungsbibliothek.
  4. YAGNI, schreiben Sie einfach SQL direkt in die Anwendungslogik.

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. HCREATE 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 wirkt INSERT, UPDATEoder DELETE, 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.


2 wie geschrieben geht im Wesentlichen von einer schreibgeschützten Datenbank aus. Gespeicherte Prozeduren waren für Abfragen, die geändert wurden, keine Seltenheit.
jpmc26

@ jpmc26: Ich beschreibe Schreibvorgänge in Klammern ... hattest du eine konkrete Empfehlung zur Verbesserung dieser Antwort?
Kevin

Hm. Entschuldigung für das Kommentieren, bevor die Antwort vervollständigt und dann abgelenkt wird. Aktualisierbare Ansichten erschweren es jedoch, festzustellen, wo eine Tabelle aktualisiert wird. Das Beschränken von Aktualisierungen auf direkt in den Tabellen, unabhängig vom Mechanismus, hat seine Vorteile im Hinblick auf das Verständnis der Codelogik. Wenn Sie die Logik auf die Datenbank beschränken, können Sie dies ohne gespeicherte Prozeduren nicht erzwingen. Sie bieten außerdem den Vorteil, dass mehrere Vorgänge mit einem einzigen Anruf möglich sind. Fazit: Ich denke nicht, dass Sie so hart auf sie sein sollten.
jpmc26

@ jpmc26: Das ist fair.
Kevin

8

Wird es als Anti-Pattern angesehen, SQL in den Quellcode zu schreiben?

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.

nimm an, dass er meinte; entweder:

1) Verwenden Sie LINQ

oder

2) Verwenden Sie gespeicherte Prozeduren für SQL

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.

Der Vorteil von Stored Procedures besteht meiner Meinung nach darin, dass SQL-Entwickler in den Entwicklungsprozess einbezogen werden können (Schreiben von Stored Procedures usw.).

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.

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?

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.


1
Vielen Dank. +1 für "Hardcoding-SQL-Anweisungen können dazu führen, dass Sie Ihre Anwendung eng an die Datenbank-Engine koppeln." Ich frage mich, ob er sich auf SQL Server anstatt auf SQL bezog, dh SQLConnection anstelle von dbConnection verwendete. SQLCommand anstelle von dbCommand und SQLDataReader anstelle von dbDataReader.
w0051977

Ich bezog mich auf die Verwendung von Ausdrücken, die nicht ANSI-konform sind. Zum Beispiel: select GETDATE(), ....GETDATE () ist die Datumsfunktion von SqlServer. In anderen Enginees hat die Funktion einen anderen Namen, einen anderen Ausdruck, ...
Laiv

14
"Vendor Lock-In" ... Wie oft migrieren Personen / Unternehmen tatsächlich die Datenbank ihres vorhandenen Produkts auf ein anderes RDBMS? Selbst in Projekten, die ausschließlich ORM verwenden, habe ich das noch nie erlebt: In der Regel wird die Software auch von Grund auf neu geschrieben, da sich die Anforderungen zwischenzeitlich geändert haben. Deshalb kommt mir das Nachdenken wie eine "vorzeitige Optimierung" vor. Ja, es ist total subjektiv.
Olivier Grégoire

1
Es ist mir egal, wie oft passiert. Es ist mir egal, es kann passieren. In Greenfield-Projekten betragen die Kosten für die Implementierung einer von der Datenbank abstrahierten DAL fast 0. Eine mögliche Migration ist dies nicht. Die Argumente gegen ORM sind ziemlich schwach. ORMs sind nicht wie vor 15 Jahren, als Hibernate noch recht grün war. Was ich gesehen habe, sind viele "Standard" -Konfigurationen und ziemlich schlechte Datenmodellentwürfe. Es ist wie bei vielen anderen Tools, viele Leute machen das Tutorial "Erste Schritte" und es ist ihnen egal, was unter der Haube passiert. Das Tool ist nicht das Problem. Das Problem ist, wer nicht weiß, wie und wann er es verwenden soll.
Laiv,

Auf der anderen Seite ist der Verkäufer nicht unbedingt schlecht. Wenn ich gefragt würde, würde ich sagen, dass ich nicht mag . Ich bin jedoch bereits an Spring, Tomcat, JBoss oder Websphere gebunden (noch schlimmer). Die, die ich vermeiden kann, tue ich. Mit denen kann ich nicht einfach leben. Es ist eine Frage der Vorlieben.
Laiv

3

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.


Wenn Sie zulassen, dass DBAs Ihre SQL ändern, ohne die Anwendung zu aktualisieren, wird Ihre Anwendung effektiv in zwei separat entwickelte, separat bereitgestellte Entitäten aufgeteilt. Sie müssen jetzt den Schnittstellenvertrag zwischen diesen verwalten, die Freigabe von voneinander abhängigen Änderungen synchronisieren usw. Dies kann eine gute oder eine schlechte Sache sein, aber es ist viel mehr als "Ihre gesamte SQL an einem Ort", es ist weit entfernt architektonische Entscheidung.
IMSoP

2

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

    string query = 
    @"SELECT foo, bar
      FROM table
      WHERE id = @tn";

7
Das auffälligste Problem dabei ist die Frage, woher dieser Wert 42 stammt. Verketten Sie diesen Wert in die Zeichenfolge? Wenn ja, woher kommt es? Wie wurde es geschrubbt, um SQL-Injection-Angriffe abzuschwächen? Warum zeigt dieses Beispiel keine parametrisierte Abfrage?
Craig

Ich wollte nur die Formatierung zeigen. Sorry, ich habe vergessen, es zu parametrieren. Nun behoben nach Bezug auf msdn.microsoft.com/library/bb738521(v=vs.100).aspx
rleir

+1 für die Bedeutung der Formatierung, obwohl ich behaupte, dass SQL-Zeichenfolgen unabhängig von der Formatierung ein Codegeruch sind.
Charles Burns

1
Bestehen Sie auf der Verwendung eines ORM? Wenn ein ORM nicht verwendet wird, verwende ich für ein kleineres Projekt eine Shim-Klasse mit eingebettetem SQL.
Rleir

SQL-Strings sind definitiv kein Codegeruch. Ohne ORM würde ich sie als Manager und Architekt aus Wartungs- und manchmal auch aus Leistungsgründen zu SPs ermutigen.
Sentinel

1

Ich kann Ihnen nicht sagen, was Ihr Kollege gemeint hat. Aber ich kann das beantworten:

Hat es einen Vorteil, eine SQL-Anweisung zu erstellen?

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:

List<UUID> ids = select(person.id).from(person).fetch();

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 personVariable 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 ...


Um es klar auszudrücken: Die Verwendung von vorbereiteten Anweisungen verhindert nicht die SQL-Injection. Die Verwendung von vorbereiteten Anweisungen mit gebundenen Variablen ist ausreichend. Es ist möglich, vorbereitete Anweisungen zu verwenden, die aus nicht vertrauenswürdigen Daten erstellt wurden.
Andy Lester

1

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.


+1 Guter Punkt. Supportfähigkeit ist wichtiger als die meisten anderen Überlegungen, seien Sie also nicht zu schlau :) Wenn Sie ein ORM-Shop sind, vergessen Sie nicht, dass es Fälle gibt, in denen ORM nicht die Antwort ist und Sie direktes SQL schreiben müssen. Optimieren Sie nicht vorzeitig, aber es wird Zeiten in nicht-trivialen Anwendungen geben, in denen Sie diesen Weg gehen müssen.
Mcottle

0

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.


0

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.

var query = "select * from accounts";

if(users.IsInRole('admin'))
{
   query += " join secret_balances";
}

Ich schlage vor, einen SQL-Abfrage-Generator zu verwenden


Es mag sein, dass Sie nur eine Kurzform verwenden, aber es ist eine wirklich schlechte Idee, "SELECT *" blind zu verwenden, weil Sie Felder zurückholen, die Sie nicht benötigen (Bandbreite !!). Auch wenn ich kein Problem mit der bedingten Admin-Klausel habe es führt einen sehr glatten Hang hinunter zu einer bedingten "WHERE" -Klausel und das ist eine Straße, die direkt zur Aufführungshölle führt.
Mcottle

0

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.


Falsch ...........
Sentinel

Denken Sie, dass Ihr Kommentar für jemanden hilfreich ist?
Bikeman868

Das ist einfach falsch. Angenommen, wir haben ein Web-API2-Projekt mit EF als Datenzugriff und Azure Sql als Speicher. Nein, wir wollen EF loswerden und handgefertigtes SQL verwenden. Das DB-Schema wird in einem SSDT SQL Server-Projekt gespeichert. Bei der Migration des DB-Schemas muss sichergestellt werden, dass die Codebasis mit dem DB-Schema synchronisiert und vollständig getestet wurde, bevor die Änderung in einen Test übernommen wird db in Azure.Eine Codeänderung umfasst das Verschieben an einen App Service-Bereitstellungssteckplatz, was 2 Sekunden dauert. Darüber hinaus bietet handgefertigtes SQL Leistungsvorteile gegenüber gespeicherten Prozeduren, obwohl das Gegenteil der Fall ist.
Sentinel

In Ihrem Fall kann die Bereitstellung Sekunden dauern, dies ist jedoch bei vielen Personen nicht der Fall. Ich habe nicht gesagt, dass gespeicherte Prozeduren besser sind, nur dass sie unter bestimmten Umständen einige Vorteile haben. Meine letzte Aussage ist, dass, wenn diese Umstände nicht zutreffen, das Einfügen von SQL in die Anwendung sehr gültig ist. Wie widerspricht das dem, was Sie sagen?
Bikeman868

Gespeicherte Prozeduren sind handgefertigtes SQL ???
Bikeman868
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.