Cosa è un ORM



A cura di Giovanni Arcifa,


Cosa è un ORM

Attraverso l’uso di un ORM, possiamo creare delle classi che rappresentino il dominio della nostra applicazione, indipendentemente da come queste sono strutturate sul database. Sarà poi compito dell’ORM tradurre i risultati delle query in oggetti e, viceversa, tradurre gli oggetti in comandi per aggiornare il Database. L’insieme delle classi create prende il nome di Object Model.

Prendiamo in esame la gestione di un ordine. Le classi di cui sicuramente avremo bisogno saranno Order, OrderDetail e Customer. In questo caso, le classi hanno una struttura speculare con le tabelle del database, ma non sempre è così. La teoria che sta dietro agli aggetti e completamente diversa dalla teoria che è alla base dei dati relazionali e questa diversità porta ad avere classi diverse dalle tabelle. Il primo esempio di questa diversità risiede nella differente granularità. Un cliente, in genere, ha un indirizzo di fatturazione e uno di spedizione (che possono coincidere o no). Per rappresentare questi dati nel database, creiamo un tabella Customers con indirizzo, CAP, città e nazione per entrambe le tipologie di indirizzi. Quando invece creiamo le classi, la cosa migliore è crearne una con le proprietà di un indirizzo, la chiameremo AddressInfo e poi aggiungere alla classe Custome due proprietà composte per la gestione dei due indirizzi. Questo significa avere una tabella lato DB (Customers) e due classi lato Object Model (Customer e AddressInfo).

Notate come la proprietà ShipAddress della classe Order e la proprietà Address della classe Customer siano proprietà composte.

Un altro esempio è fornito dalla diversa modalità di relazione fra i dati. In un database, le relazioni tra i record sono mantenute tramite foreign key, le quali altro non sono che colonne. Ad esempio per associare l’ordine ad un cliente, mettiamo nella tabella degli ordini una colonna che contenga l’id del cliente. Nell’Object Model le relazioni si esprimono usando direttamente gli oggetti. Quindi, per mantenere l’associazione tra l’ordine e il cliente, aggiungiamo la proprietà Customer alla classe Order.

Le differenze si amplificano ulteriormente quando usiamo l’ereditarietà. Utilizzare questa tecnica nel mondo a oggetti è una cosa normalissima. Tuttavia, nel mondo relazionale non vi è traccia di ereditarietà. Supponendo di avere un Object Model con le classi Customer e Supplier che ereditano dalla classe Company, come possiamo avere una simile rappresentazione nel database?.

Risolvere manualmente tutte queste complessità (e anche altre) non è affatto banale ed è per questo motivo che, da tempo, esistono dei framework che coprono queste e altre necessità. Questi framework prendono il none di ORM, in quanto lavorano come (M)apper tra (O)ggetti e dati (R)elazionali. In questo modo le diversità tra i due mondi sono gestite dall’ORM, che ci lascia liberi di preoccuparci del solo codice di business.

Gli ORM agiscono come mapper, cioè mappano le classi e le relative proprietà con le tabelle e le colonne nel database. Il vantaggio che ne deriva è che possiamo evitare di scrivere query verso il database, ma possiamo scriverle verso l’Object Model in un linguaggio specifico dell’ORM, che poi si occuperà di creare il codice SQL necessario. In termini di logica di business questo è un enorme vantaggio. Lo stesso ragionamento vale per gli aggiornamenti sul database. Noi ci preoccupiamo solo di modificare gli oggetti e poi demandiamo all’ORM la persistenza di questi sul database.

Ora dovrebbe essere più chiaro cosa significhi avere un’applicazione disaccoppiata dal database. In conclusione, un ORM è una parte di software molto potente, ma allo stesso tempo molto complessa e pericolosa, poiché il livello di astrazione che introduce rischia di farci dimenticare che c’è un database, e questo è negativo. Dobbiamo sempre controllare le query generate dal ORM e verificare le istruzioni di update, per essere sicuri che le performance corrispondano ai requisiti. Per concludere l'uso di un ORM favorisce il raggiungimento di più alti standard qualitativi software, migliorando in particolare le caratteristiche di correttezza, manutenibilità, evolvibilità e portabilità. Rende l’accesso ai dati più astratto e portatile ed elimina la scrittura di codice ripetitivo come il mapping dei campi di una query result sulle proprietà di un oggetto e viceversa e la scrittura di codice CRUD. Pensiamo ad esempio ad un progetto con 200 tabelle.

1 Tabella = 4 operazioni CRUD

200 tabelle= 4*200= 800 operazioni CRUD 

Sapete cosa significa.

 

Ovviamente c’è un prezzo da pagare dovuto ad una maggiore complessità, ed in caso di problemi si perde parecchio tempo nel debugging e nel tuning. All'inizio si avrà una curva d'apprendimento da scalare velocemente per mettersi in pari con quello che si potrebbe "fare in casa" ma, posto che il sistema supporti tutte le esigenze (e nel caso degli ORM è difficile che non lo faccia e che non sia estensibile in tal senso), in seguito il tempo speso per imparare la nuova tecnologia potrà essere usato per fare ben altra roba.