Wie kann ich die Verwendung eines ORM anstelle von gespeicherten Prozeduren vorschlagen?


31

Ich arbeite in einem Unternehmen, das nur gespeicherte Prozeduren für den gesamten Datenzugriff verwendet, was es sehr ärgerlich macht, unsere lokalen Datenbanken bei jedem Commit, den wir ausführen müssen, synchron zu halten. Ich habe in der Vergangenheit einige grundlegende ORMs verwendet und finde die Erfahrung viel besser und sauberer. Ich möchte dem Entwicklungsleiter und dem Rest des Teams vorschlagen, ein ORM für die zukünftige Entwicklung zu verwenden (der Rest des Teams ist nur mit gespeicherten Prozeduren vertraut und hat noch nie etwas anderes verwendet). Die aktuelle Architektur ist .NET 3.5, geschrieben wie .NET 1.1, mit "God-Klassen", die eine seltsame Implementierung von ActiveRecord verwenden und untypisierte DataSets zurückgeben, die in Code-Behind-Dateien durchlaufen werden. Die Klassen funktionieren ungefähr so:

class Foo { 
    public bool LoadFoo() { 
        bool blnResult = false;
        if (this.FooID == 0) { 
            throw new Exception("FooID must be set before calling this method.");
        }

        DataSet ds = // ... call to Sproc
        if (ds.Tables[0].Rows.Count > 0) { 
            foo.FooName = ds.Tables[0].Rows[0]["FooName"].ToString();
            // other properties set
            blnResult = true;
        }
        return blnResult;
    }
}

// Consumer
Foo foo = new Foo();
foo.FooID = 1234;
foo.LoadFoo();
// do stuff with foo...

Es gibt so gut wie keine Anwendung von Entwurfsmustern. Es gibt überhaupt keine Tests (niemand weiß, wie man Unit-Tests schreibt, und das Testen erfolgt durch manuelles Laden der Website und Herumstöbern). Durchsuchen Sie unsere Datenbank mit 199 Tabellen, 13 Ansichten, 926 gespeicherten Prozeduren und 93 Funktionen. Ungefähr 30 Tabellen werden für Batch-Jobs oder externe Dinge verwendet, der Rest wird in unserer Kernanwendung verwendet.

Lohnt es sich überhaupt, in diesem Szenario einen anderen Ansatz zu verfolgen? Ich spreche davon, nur voranzukommen, weil wir den vorhandenen Code nicht umgestalten dürfen, da "es funktioniert", sodass wir die vorhandenen Klassen nicht zur Verwendung eines ORM ändern können, aber ich weiß nicht, wie oft wir stattdessen brandneue Module hinzufügen Ich bin mir nicht sicher, ob ein ORM der richtige Ansatz ist (zu viel in gespeicherte Prozeduren und DataSets investiert). Wenn es die richtige Wahl ist, wie soll ich den Fall für die Verwendung einer darstellen? Der einzige Vorteil, den ich mir vorstellen kann, ist, saubereren Code zu haben (auch wenn dies möglicherweise nicht der Fall ist, da die aktuelle Architektur nicht der Fall ist). Ohne Rücksicht auf ORMs würden wir ORMs grundsätzlich auf zukünftige Module ausrichten, aber die alten würden immer noch die DataSets verwenden), und es wäre weniger mühsam, sich daran zu erinnern, welche Prozedurskripte ausgeführt wurden und welche ausgeführt werden müssen. usw. aber das wars auch schon und ich weiß nicht, wie überzeugend ein argument wäre. Die Wartbarkeit ist ein weiteres Problem, das außer mir niemand zu befürchten scheint.


8
Klingt so, als hätten Sie mehr Probleme, als nur das Team von der Verwendung von ORMs zu überzeugen. Mir scheint, dass Ihrem Team einige gute Entwicklungspraktiken (z. B. Entwurfsmuster, Komponententests) nicht bekannt sind. Dies sind wichtigere Themen, die Sie angehen müssen.
Bernard

6
Ironischerweise habe ich in den letzten fünf Jahren meiner Entwicklung vielleicht nur eine Handvoll Leute / Teams getroffen, die sich mit Dingen wie Entwurfsmustern und Komponententests auskennen. Normalerweise bin ich der einzige in der Firma, der über diese Dinge Bescheid weiß.
Wayne Molina

3
@ Wayne M: Ich finde das etwas störend, bin aber auch nicht überrascht.
Bernard

2
Ich fand es sehr ... entmutigend. Es ist seltsam, wenn man etwas vorschlägt und einen "Hirsch im Scheinwerferlicht" -Look bekommt, der anzeigt, dass die andere Person nicht die vage Ahnung hat, wovon man spricht oder warum irgendjemand jemals darüber nachdenken würde, das zu tun. Ich habe das schon einige Male in der Vergangenheit erlebt.
Wayne Molina

2
Ich bin ein großer Fan von Stored Procedure, daher ist mein Kommentar voreingenommen, aber ich bin mit der ganzen Prämisse überhaupt nicht einverstanden. Du magst ORM und willst es benutzen, das ist in Ordnung. Der Rest des Teams ist jedoch mit gespeicherten Prozessen einverstanden. Warum zwingen Sie sie zu dem, was Sie mögen?
Darknight

Antworten:


47

Gespeicherte Prozeduren sind schlecht, oft langsam und ungefähr so ​​effizient wie gewöhnlicher clientseitiger Code.

[Die Beschleunigung ist normalerweise auf die Art und Weise zurückzuführen, wie die Client- und die Schnittstelle für gespeicherte Prozeduren entworfen wurden und wie Transaktionen als kurze, fokussierte SQL-Bursts geschrieben werden.]

Gespeicherte Prozeduren sind einer der schlechtesten Orte, an denen Code abgelegt werden kann. Es unterteilt Ihre Anwendung in zwei Sprachen und Plattformen nach häufig zufälligen Regeln.

[Diese Frage wird mit -30 bewertet, da viele, viele Leute der Meinung sind, dass gespeicherte Prozeduren magische Kräfte haben und trotz der von ihnen verursachten Probleme verwendet werden müssen.]

Das Verschieben des gesamten Codes für gespeicherte Prozeduren auf den Client erleichtert die Arbeit für alle erheblich.

Sie müssen das Schema und das ORM-Modell von Zeit zu Zeit aktualisieren. Schemaänderungen sind jedoch von ORM-Änderungen isoliert, was eine gewisse Unabhängigkeit zwischen Anwendungen und Datenbankschema ermöglicht.

Sie können alle gespeicherten Prozeduren testen, reparieren, warten, verstehen und anpassen, während Sie sie umschreiben. Ihre App wird ungefähr gleich ausgeführt und weniger anfällig, da Sie nicht mehr in zwei verschiedene Technologien einbrechen.

ORMs sind keine Zauberei, und gute Fähigkeiten im Datenbankdesign sind absolut notwendig, damit sie funktionieren.

Programme mit viel Client-SQL können außerdem langsam werden, weil sie die Transaktionsgrenzen nicht genau kennen. Einer der Gründe, warum gespeicherte Prozeduren schnell zu sein scheinen, besteht darin, dass gespeicherte Prozeduren ein sehr sorgfältiges Design von Transaktionen erzwingen.

ORMs erzwingen nicht auf magische Weise ein sorgfältiges Transaktionsdesign. Das Transaktionsdesign muss noch genauso sorgfältig durchgeführt werden wie beim Schreiben gespeicherter Prozeduren.


19
+1, weil gespeicherte Prozeduren ein totaler Arbeitsschmerz sind
Gary Rowe

3
: '(Ich habe kein Problem mit gespeicherten Prozeduren. Es ist nur eine weitere Abstraktionsebene für mich.
Mike Weller

3
Wenn wir SP erstellen, speichert das Datenbankmodul es als kompiliertes Formular und erstellt einen Ausführungspfad, damit es so schnell wie möglich ausgeführt wird. ORM sendet jedoch jedes Mal SQL, das vom Datenbankmodul kompiliert und ausgeführt werden muss. Ich denke, es wird langsamer sein, ein ORM anstelle von Stored Procedure zu verwenden.
DeveloperArnab

4
Lustig. Wir sind von einem ORM zu gespeicherten Prozeduren zurückgekehrt, nur weil ... SPEED. Nicht die Zeit, die wir für die Programmierung benötigen, sondern die Zeit, die ein ORM benötigt, um Objekte zu materialisieren, ein Objekt nachzuschlagen und auf verschiedenen Clients zu aktualisieren. SP war verdammt viel schneller. Ein Beispiel: Das Lesen von 30.000 Objekten aus der DB mit einem neuen modernen ORM braucht ... na ja. Auszeit nach 2 Minuten. Aufrufen der gespeicherten Prozedur und Abrufen des Ergebnisses - 2 Sekunden. Ja - es gibt viele Tricks wie Paging, um das Rufzeichen einer Datenbank auf ein Vielfaches zu reduzieren - aber ein großer Unterschied, wenn es nur darum geht, ob ein ORM verwendet werden kann oder nicht
Offler 28.04.15

2
@DeveloperArnab: Das mag vor 20 Jahren so gewesen sein, aber moderne DB-Engines sind ziemlich ausgefeilt und können zuvor ausgeführte Abfragen erkennen und Ausführungspläne wiederverwenden. Der Geschwindigkeitsunterschied ist heutzutage so gering, dass der zusätzliche Aufwand von SPs kaum gerechtfertigt ist.
Whatsisname

20

Gespeicherte Prozeduren sind gut, schnell und sehr effizient und der ideale Ort, um Ihren datenbezogenen Code abzulegen. Das Verschieben des gesamten Codes auf den Client vereinfacht die Arbeit für Sie als Cliententwickler geringfügig (geringfügig, da Sie das Schema und das ORM-Modell nach dem Festschreiben von Änderungen noch aktualisieren müssen), aber Sie verlieren den gesamten vorhandenen Code und nehmen Änderungen vor Ihre App ist langsamer und wahrscheinlich fragiler, wenn man bedenkt, dass all diese SQL-Kenntnisse verloren gehen.

Ich frage mich, ob die Datenbankadministratoren dort sitzen und sagen: "Oh, bei jedem Commit muss ich den Client erneut herunterfahren, wir sollten den gesamten Code stattdessen in DB-Formulare verschieben."

In Ihrem Fall sollten Sie in der Lage sein, das vorhandene benutzerdefinierte ORM (dh Ihre lustigen Klassen) ohne Verluste durch das eines anderen zu ersetzen, mit Ausnahme von Änderungen an der Art und Weise, wie Ihr Code-Behind-Code geschrieben wird. Sie können die SPs auch behalten, da die meisten (alle?) ORMs sie gerne anrufen. Daher würde ich empfehlen, diese "Foo" -Klassen durch ein ORM zu ersetzen und von dort aus fortzufahren. Ich würde nicht empfehlen, Ihre SPs zu ersetzen.

PS. Es scheint, dass Sie in den Code-Behind-Klassen viele gemeinsame Codes haben, die sie zu einem eigenständigen Entwurfsmuster machen. Was denkst du, ist ein Designmuster an erster Stelle! (ok, es ist vielleicht nicht das beste oder sogar ein gutes, aber es ist immer noch ein DP)

Bearbeiten: und jetzt mit Dapper , ist jeder Grund, Sprocs über ein schweres ORM zu vermeiden, weg.


3
+1 ist der naheliegende erste Schritt, zu einem ORM zu wechseln und dort die Ergebnisse der vorhandenen gespeicherten Prozeduren Objekten zuzuordnen. Werde den ganzen ds.Tables[0].Rows[0]["FooName"].ToString()Mist los . Manager liebt gespeicherte Prozeduren? Er darf sie behalten. Es wäre jedoch physikalisch unmöglich zu behaupten, dass es eine schlechte Sache war, all den sich wiederholenden Code von Boilerplate in etwas zu verschieben, das beispielsweise von LINQ to SQL generiert wurde.
Carson63000

11
Nun, ich kann nicht glauben, wie viel "falsch" in deinem Beitrag ist. Ihr Vergleich mit einem DBA, der darüber jammert, den Code ziehen zu müssen, ist unangemessen und völlig sinnlos. Erstens ist die Datenbank ein SERVICE, mit dem Daten gespeichert und abgerufen werden können. LOGIC geht, wie der Name schon sagt, in die Business Logic Layer über, die Teil des API-Codes ist. App fragiler weg von Sprocs? Meinst du das ernst oder trollst du nur? TDD eine App mit Logik in Sprocs und sag mir, wie viel Spaß das macht. Auch ORMs sollen nicht geschaltet werden. Datenbanken sind, da sie nur ein SERVICE sind.
Matteo Mosca

5
Ich kann nicht wirklich verstehen, warum manche Leute denken, dass die Datenbank eine Art heiliges Land ist, in dem alles heilig ist. Denk darüber nach. Wenn ein Drittanbieter Ihnen einen Service zur Verfügung stellt, erhalten Sie direkten Zugriff auf seine Datenbank, oder maskieren sie ihn hinter einer API? Verwenden Sie einen beliebigen Google-Dienst, um ein beliebtes Beispiel zu verwenden. Sie, Entwickler, stellen eine Verbindung zu ihrer öffentlichen API her, Sie wissen nicht einmal, welche Datenbank sich darunter befindet oder ob es überhaupt eine Datenbank gibt. So entwerfen Sie eine solide und entkoppelte Software. Auf Datenbanken kann nicht direkt von Anwendungen zugegriffen werden. Dafür gibt es Mittelschichten.
Matteo Mosca

5
@ Matteo Mosca: sicher, aber wie greift die Middleware auf die DB zu ... es ist ein Client für die DB. "client" bedeutet nicht "GUI" oder "Desktop-App". In den Anwendungsebenen gibt es viele Grauzonen. Vergeben Sie die Validierung in die GUI oder in die Server- / Geschäftslogik? Der Server sollte ein sauberes Design haben, was jedoch die Leistung und die Reaktionsfähigkeit der Benutzer beeinträchtigt. In ähnlicher Weise fügen Sie häufig eine Logik in die Datenbank ein, um die Leistung und (in diesem Fall) die Datenkorrektheit zu verbessern.
gbjbaanb

4
Es tut mir leid, aber ich bin immer noch anderer Meinung. An dem Tag, an dem Sie Ihre Anwendung in einer anderen Umgebung bereitstellen müssen, in der Sie nicht über dieselbe DB-Technologie verfügen, die Sie verwendet haben, können Sie Ihre App nicht ausführen, da Sie nicht über alle diese Sprocs in der neuen Datenbank verfügen .. und selbst wenn Sie sie neu erstellen (das ist ein großer Aufwand), können sie aufgrund der Unterschiede bei SQL-Dialekten usw. unterschiedlich sein. Eine zentralisierte API mit Logik und Validierung, die über einen Standard (wie SOAP oder REST) ​​verfügbar gemacht wird, löst dieses Problem Problem und fügt Testbarkeit, Versionierung und Konsistenz hinzu.
Matteo Mosca

13

Sie scheinen zu versuchen, Ihr Team von einem Extrem (gespeicherte Prozeduren und Datensätze) zu einem anderen (einem vollständigen ORM) zu führen. Ich denke, es gibt andere, inkrementellere Änderungen, die Sie an der Implementierung vornehmen können, um die Codequalität Ihrer Datenzugriffsebene zu verbessern, die Ihr Team möglicherweise eher akzeptiert.

Der halbfertige Implementierungscode für aktive Datensätze, den Sie veröffentlicht haben, ist nicht besonders elegant. Ich würde empfehlen, das Repository-Muster zu untersuchen, das einfach zu verstehen und zu implementieren ist und bei .NET-Entwicklern sehr beliebt ist. Dieses Muster wird oft mit ORMs assoziiert, aber es ist genauso einfach, Repositorys mit ADO.NET zu erstellen.

Wie für DataSets - igitt! Mit Ihren Klassenbibliotheken lässt sich viel einfacher arbeiten, wenn Sie statisch (oder sogar dynamisch) typisierte Objekte zurückgeben. Ich glaube, diese Abbildung erklärt meine Meinung zu DataSet besser als ich könnte.

Sie können die gespeicherten Prozesse auch löschen, ohne zu einem ORM zu springen - es ist nichts Falsches an der Verwendung von parametrisiertem SQL. In der Tat würde ich es definitiv der Verwendung von gespeicherten Prozessen vorziehen, es sei denn, Sie haben komplexe Prozeduren, die mehrere Roundtrips zum Server ersparen. Ich hasse es auch, wenn ich eine alte Datenbank öffne und eine endlose Liste von CRUD-Prozeduren sehe.

Ich rate nicht von der Verwendung von ORMs ab - ich benutze sie im Allgemeinen für die meisten Projekte, an denen ich arbeite. Ich kann jedoch nachvollziehen, warum der Versuch, eines in dieses Projekt und Ihr Team einzuführen, möglicherweise zu viel Reibung führt. Das klingt so, als hätten sie vor etwa acht Jahren aufgehört, neue Dinge zu lernen. Trotzdem würde ich auf jeden Fall einen Blick auf die neue Generation von "Micro ORMs" werfen, wie Dapper (der diese Site nicht weniger antreibt ) und Massive , die beide unglaublich einfach zu bedienen sind und Sie näher am SQL halten als a Ein typisches ORM, und das Ihr Team möglicherweise eher akzeptiert.


2
Ich denke, das Problem ist, dass es zu dem Zeitpunkt, als die App geschrieben wurde, keine wirklich wichtigen ORMs für .NET gab. Es wurde also anders gemacht (in ASP.NET 1.1), und niemand hat jemals daran gedacht, es anders zu machen (oder irgendetwas anderes) Bis ich vor ein paar Monaten dazu kam.
Wayne Molina

1
+1 für Dapper. Ich habe gerade damit begonnen, es in einem Projekt zu verwenden, und es ist äußerst einfach zu implementieren und zu verwenden. Ich bin schon ein großer Fan.
SLoret

4

Ich bin in einer ähnlichen Situation, unsere Hardware, Macht und Politik lehnen sich an die Seite der Datenbank, also durchläuft alles eine gespeicherte Prozedur. Leider sind sie für einen Codierer eine Qual, insbesondere wenn es um die Generierung von Metadaten und Code geht, da gespeicherte Prozeduren nicht so umfangreiche Metadaten enthalten wie Tabellen.

Unabhängig davon können Sie mit gespeicherten Prozessen immer noch eleganten und sauberen Code schreiben. Ich implementiere derzeit das Repository-Muster selbst mit allen gespeicherten Prozeduren. Ich würde vorschlagen, FluentAdo.net nach seiner brillanten Idee zu durchsuchen, wenn Sie Daten von einem Datenleser zurück auf Ihre Geschäftsobjekte übertragen. Ich habe einen Teil dieser Idee übernommen und für meine eigene Lösung verwendet.


3

JFTR - Ich bin ein niedriger PHP-Entwickler, aber das klingt nach einer überwiegend politischen Angelegenheit.

In Anbetracht des Ausmaßes der "Fäulnis", die die App stützt, würde es - abgesehen von den Best Practices - einen erheblichen Aufwand geben, sie zu beseitigen. Das hört sich so an, als würde es an das Neuschreiben von Territorien angrenzen.

Können Sie garantieren, dass die von Ihnen vorgeschlagene Alternative Vorteile bringt, um die Kosten für das Unternehmen zu rechtfertigen? Ich vermute, dass es schwierig sein könnte, den ROI dieses Unternehmens an das Unternehmen zu verkaufen. Es sei denn, die App ist instabil oder Sie können den finanziellen Erfolg der Überarbeitung nachweisen - dies könnte sich als schwierig erweisen.

Ist ORM die einzige Alternative zu SPROCS? Es gibt ein paar Designmuster zwischen einem vollständigen ORM und Vanilla SQL. Vielleicht können Sie den Prozess starten, indem Sie diese SPROCS nach und nach aus der DB in eine DBAL bringen. Es besteht natürlich die Gefahr, dass dies mit der Zeit zu einem Homebrew-ORM wird - aber Sie wären dem Ziel einen Schritt näher gekommen.


2

Wir sind vor ein paar Jahren von SP zu ORM gewechselt.

In einem Fall mussten wir 80 Tabellen aktualisieren. Das alte Schätzmodell hätte hierfür mit entlib und SP 80 Stunden veranschlagt. Wir haben es in 10 gemacht :)

Dadurch konnten wir den Zeitaufwand für die Entwicklung der Datenzugriffsschicht um 80% reduzieren.


1
Und Sie konnten das Tabellen-Update nicht schreiben, warum?
Darknight

Dabei wurde ein komplexes Objekt in den Speicher aufgenommen und in einer relationalen Datenbank für die Berichterstellung gespeichert. Wir haben ein Programm geschrieben, das das Objekt reflektiert, um die Tabellenstruktur zu erstellen.
Shiraz Bhaiji

-1

Mir kommt eher vor, dass das zugrunde liegende Problem darin besteht, dass Ihre Bereitstellungen nicht ordnungsgemäß und automatisch funktionieren.

Es ist möglicherweise einfacher, eine Continuous Build-Engine einzurichten, die weiß, wie die Datenbanken nach jedem Commit nach Bedarf bearbeitet werden.

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.