Dopo aver utilizzato Hibernate sulla maggior parte dei miei progetti per circa 8 anni, sono approdato in un'azienda che ne scoraggia l'utilizzo e desidera che le applicazioni interagiscano con il DB solo tramite stored procedure.
Dopo averlo fatto per un paio di settimane, non sono stato in grado di creare un ricco modello di dominio dell'applicazione che sto iniziando a costruire e l'applicazione sembra solo uno (orribile) script transazionale.
Alcuni dei problemi che ho riscontrato sono:
- Impossibile navigare nel grafico degli oggetti poiché le procedure memorizzate caricano solo la quantità minima di dati, il che significa che a volte abbiamo oggetti simili con campi diversi. Un esempio è: abbiamo una procedura memorizzata per recuperare tutti i dati da un cliente e un altro per recuperare le informazioni sull'account più alcuni campi dal cliente.
- Molta parte della logica finisce nelle classi helper, quindi il codice diventa più strutturato (con entità usate come vecchie strutture C).
- Codice di scaffolding più noioso, poiché non esiste un framework che estrae i set di risultati da una procedura memorizzata e li inserisce in un'entità.
Le mie domande sono:
- qualcuno si è trovato in una situazione simile e non era d'accordo con l'approccio della procedura del negozio? che cosa hai fatto?
- C'è un reale vantaggio nell'utilizzare le procedure memorizzate? a parte il punto sciocco di "nessuno può emettere una tabella di rilascio".
- C'è un modo per creare un dominio ricco utilizzando le procedure memorizzate? So che esiste la possibilità di utilizzare AOP per iniettare DAO / repository in entità per poter navigare nel grafico degli oggetti. Non mi piace questa opzione perché è molto vicina al voodoo.
Conclusione
Innanzitutto, grazie a tutti per le risposte. La conclusione che sono arrivato è che gli ORM non consentono la creazione di modelli Rich Domain (come menzionato da alcune persone), ma semplifica la quantità di lavoro (spesso ripetitivo). Quella che segue è una spiegazione più dettagliata della conclusione, ma non si basa su dati concreti.
La maggior parte delle applicazioni richiede e invia informazioni ad altri sistemi. Per fare ciò, creiamo un'astrazione nei termini del modello (ad esempio un evento aziendale) e il modello di dominio invia o riceve l'evento. L'evento di solito richiede un piccolo sottoinsieme di informazioni dal modello, ma non l'intero modello. Ad esempio in un negozio online, un gateway di pagamento richiede alcune informazioni utente e il totale per addebitare un utente, ma non richiede la cronologia degli acquisti, i prodotti disponibili e tutta la base clienti. Quindi l'evento ha un set di dati piccolo e specifico.
Se prendiamo il database di un'applicazione come un sistema esterno, allora dobbiamo creare un'astrazione che ci consenta di mappare le entità del modello di dominio al database ( come menzionato da NimChimpsky , usando un mappatore di dati). L'ovvia differenza è che ora è necessario creare una mappatura per ogni entità modello sul database (uno schema legacy o procedure memorizzate), con il dolore aggiuntivo che, poiché i due non sono sincronizzati, un'entità dominio potrebbe mappare parzialmente a un'entità database (ad es. una classe UserCredentials che contiene solo nome utente e password è mappata a una tabella Users che ha altre colonne), oppure un'entità modello di dominio potrebbe essere mappata a più di un'entità database (ad esempio se esiste un one-to- una mappatura sulla tabella, ma vogliamo tutti i dati in una sola classe).
In un'applicazione con poche entità, la quantità di lavoro extra potrebbe essere piccola se non è necessario attraversare le entità, ma aumenta quando c'è una necessità condizionale di attraversare le entità (e quindi potremmo voler implementare un tipo di 'pigro Caricamento in corso'). Man mano che un'applicazione cresce per avere più entità, questo lavoro aumenta (e ho la sensazione che aumenti in modo non lineare). La mia ipotesi qui è che non proviamo a reinventare un ORM.
Un vantaggio del trattamento del DB come un sistema esterno è che possiamo codificare situazioni in cui vogliamo che vengano eseguite 2 versioni diverse di un'applicazione, in cui ogni applicazione ha un mapping diverso. Ciò diventa più interessante nello scenario delle consegne continue alla produzione ... ma penso che ciò sia possibile anche con ORM in misura minore.
Ho intenzione di respingere l'aspetto della sicurezza, sulla base del fatto che uno sviluppatore, anche se non ha accesso al database, può ottenere la maggior parte se non tutte le informazioni memorizzate in un sistema, semplicemente iniettando codice dannoso (ad es. Non posso credere di aver dimenticato di rimuovere la riga che registra i dettagli della carta di credito dei clienti, caro signore! ).
Piccolo aggiornamento (06/06/2012)
Le procedure memorizzate (almeno in Oracle) impediscono di fare qualcosa di simile alla consegna continua con tempi di inattività pari a zero, poiché qualsiasi modifica alla struttura delle tabelle invaliderà le procedure e i trigger. Pertanto, durante il periodo di aggiornamento del DB, anche l'applicazione sarà inattiva. Oracle fornisce una soluzione per questa Redefinizione basata sull'edizione , ma i pochi DBA che ho chiesto su questa funzionalità hanno affermato che era mal implementata e non la inserivano in un DB di produzione.