Nachdem ich Hibernate für die meisten meiner Projekte ungefähr 8 Jahre lang verwendet habe, bin ich bei einem Unternehmen gelandet, das von seiner Verwendung abrät und möchte, dass Anwendungen nur über gespeicherte Prozeduren mit der Datenbank interagieren.
Nachdem ich dies einige Wochen lang getan habe, konnte ich kein umfassendes Domänenmodell der Anwendung erstellen, die ich gerade erst zu erstellen beginne, und die Anwendung sieht nur aus wie ein (schreckliches) Transaktionsskript.
Einige der Probleme, die ich gefunden habe, sind:
- Das Objektdiagramm kann nicht navigiert werden, da die gespeicherten Prozeduren nur die minimale Datenmenge laden. Dies bedeutet, dass manchmal ähnliche Objekte mit unterschiedlichen Feldern vorhanden sind. Ein Beispiel ist: Wir haben eine gespeicherte Prozedur, um alle Daten von einem Kunden abzurufen, und eine andere, um Kontoinformationen sowie einige Felder vom Kunden abzurufen.
- Ein Großteil der Logik endet in Hilfsklassen, sodass der Code strukturierter wird (mit Entitäten, die als alte C-Strukturen verwendet werden).
- Langweiliger Gerüstcode, da es kein Framework gibt, das Ergebnismengen aus einer gespeicherten Prozedur extrahiert und in eine Entität einfügt.
Meine Fragen sind:
- Hat sich jemand in einer ähnlichen Situation befunden und war nicht mit der Vorgehensweise beim Laden einverstanden? was hast du getan?
- Gibt es einen tatsächlichen Vorteil bei der Verwendung gespeicherter Prozeduren? abgesehen von dem dummen Punkt "Niemand kann eine Drop-Tabelle ausstellen".
- Gibt es eine Möglichkeit, mithilfe gespeicherter Prozeduren eine Rich-Domain zu erstellen? Ich weiß, dass es die Möglichkeit gibt, mithilfe von AOP DAOs / Repositorys in Entitäten einzufügen, um im Objektdiagramm navigieren zu können. Ich mag diese Option nicht, da sie sehr nahe an Voodoo liegt.
Fazit
Zunächst einmal vielen Dank für Ihre Antworten. Die Schlussfolgerung, die ich gezogen habe, ist, dass ORMs nicht die Erstellung von Rich Domain-Modellen ermöglichen (wie einige Leute erwähnt haben), aber den Umfang der (oft wiederholten) Arbeit vereinfachen. Das Folgende ist eine detailliertere Erläuterung der Schlussfolgerung, basiert jedoch nicht auf harten Daten.
Die meisten Anwendungen fordern Informationen an und senden sie an andere Systeme. Dazu erstellen wir eine Abstraktion in den Modellbegriffen (z. B. ein Geschäftsereignis) und das Domänenmodell sendet oder empfängt das Ereignis. Das Ereignis benötigt normalerweise eine kleine Teilmenge an Informationen aus dem Modell, jedoch nicht das gesamte Modell. Beispielsweise fordert ein Zahlungsgateway in einem Online-Shop einige Benutzerinformationen und den Gesamtbetrag an, um einem Benutzer eine Gebühr in Rechnung zu stellen, benötigt jedoch nicht den Kaufverlauf, die verfügbaren Produkte und den gesamten Kundenstamm. Die Veranstaltung hat also einen kleinen und spezifischen Datensatz.
Wenn wir die Datenbank einer Anwendung als externes System verwenden, müssen wir eine Abstraktion erstellen, die es uns ermöglicht, die Domänenmodell- Entitäten der Datenbank zuzuordnen ( wie NimChimpsky erwähnt hat , unter Verwendung eines Daten-Mappers). Der offensichtliche Unterschied besteht darin, dass wir jetzt eine Zuordnung für jede Modellentität zur Datenbank (entweder ein Legacy-Schema oder gespeicherte Prozeduren) von Hand erstellen müssen, mit dem zusätzlichen Aufwand, dass eine Domänenentität teilweise zugeordnet werden kann, da die beiden nicht synchron sind einer Datenbankentität zugeordnet werden (z. B. wird eine UserCredentials-Klasse, die nur Benutzername und Kennwort enthält, einer Users-Tabelle mit anderen Spalten zugeordnet), oder eine Domänenmodellentität kann mehreren Datenbankentitäten zugeordnet werden (z. eine Zuordnung auf dem Tisch, aber wir wollen alle Daten in nur einer Klasse).
In einer Anwendung mit einigen wenigen Entitäten kann der zusätzliche Arbeitsaufwand gering sein, wenn die Entitäten nicht transversiert werden müssen. Er erhöht sich jedoch, wenn die Entitäten unter bestimmten Bedingungen transversiert werden müssen (und daher möchten wir möglicherweise eine Art 'Lazy' implementieren Wird geladen'). Mit zunehmender Anzahl von Entitäten in einer Anwendung nimmt diese Arbeit nur zu (und ich habe das Gefühl, dass sie nicht linear zunimmt). Ich gehe hier davon aus, dass wir nicht versuchen, ein ORM neu zu erfinden.
Ein Vorteil der Behandlung der Datenbank als externes System besteht darin, dass wir Situationen umgehen können, in denen zwei verschiedene Versionen einer Anwendung ausgeführt werden sollen, wobei jede Anwendung eine andere Zuordnung hat. Dies wird im Szenario kontinuierlicher Lieferungen an die Produktion interessanter ... aber ich denke, dass dies in geringerem Maße auch mit ORMs möglich ist.
Ich werde den Sicherheitsaspekt verwerfen, auf der Grundlage, dass ein Entwickler, auch wenn er keinen Zugriff auf die Datenbank hat, die meisten, wenn nicht alle in einem System gespeicherten Informationen erhalten kann, indem er bösartigen Code einfügt (z. B. Ich kann nicht glauben, dass ich vergessen habe, die Zeile zu entfernen, in der die Kreditkartendaten der Kunden vermerkt sind, sehr geehrter Herr! ).
Kleines Update (06.06.2012)
Gespeicherte Prozeduren (zumindest in Oracle) verhindern eine kontinuierliche Zustellung ohne Ausfallzeiten, da jede Änderung der Tabellenstruktur die Prozeduren und Trigger ungültig macht. Während der Aktualisierung der Datenbank ist die Anwendung daher ebenfalls inaktiv. Oracle bietet eine Lösung für diese Edition-Based Redefinition , aber die wenigen DBAs, die ich zu diesem Feature gefragt habe, erwähnten, dass es schlecht implementiert war und nicht in eine Produktions-DB aufgenommen werden würde.