Visualizzazione post con etichetta DAO. Mostra tutti i post
Visualizzazione post con etichetta DAO. Mostra tutti i post

mercoledì 8 ottobre 2008

Ancora su Orm

Sono riuscito nel tentativo del salvataggio di una chiamata con hibernate/orm... ho in pratica trovato il modo per superare, più o meno, le restrizioni evidenziate in questo post(Alcuni problemi con gli id composti e i valori di default con Hibernate).

In pratica ho usato degli DAO molto più semplici... che non considerano in pratica le relazioni molti a molti... in pratica, all'interno della classe che rappresenta la tabella nel database, ogni riferimento a chiavi esterne... è memorizzato come un campo qualsiasi, ignorando assolutamente se nei DAO esiste una classe che potrebbe sostiurire il campo.

In pratica, prima, per esempio, se nella tabella chiamata evavo un campo id_imp che era ovviamente una chiava esterna per la tabella imp, il DAO era costituito come un field costituito da un elemento stesso della classe Imp... che a suo volta però al suo interno aveva un ID composito rappresentato dalla classe ImpId... ed è questo che pareva creare dei problemi.

Ora, con questi nuovi DAO più semplici, in un caso come quello sopra, id_imp è rappresentato nella classe Chiamata dal field chiamato idImp rappresentato da una semplice stringa... posso quindi assegnarli una semplice stringa... che rappresenta poi l'id chiave esterna di imp (imp ha il campo id come stringa)
In pratica come dovrei fare se usassi SQL.

Così sono riuscito a memorizzare senza problemi una chiamata assegnando tramite gli strumenti di HIBernate tutti i valori che mi interessano.
In realtà qualcosa di diverso c'è... tutti i campi sono memorizzati come dati primitivi, String, char, int, date... cioè come la definzione del campo nel database... tranne alcuni (pochissimi) come per esempio HdTipoContab, che è memorizzato ancora come classe... questo perchè (credo) proprio al tabella hd_tipo_contab non ha id composto (come invece il 99% delle altre tabelle) e quindi è comuinque molto semplice usarlo... anche se ho dovuto aggiungere un costruttore alla classe così come era stata creata automaticamente.

Questi DAO semplificati li ho ottenuti usando sempre Hibernate Tool, plugin di Eclipse, selezionando perà nel file di configurazione hibernate.revenge.xml solo el tabelle vere e proprie, ignorando le varie view presenti nel database, e selezionando, all'atto della creazione del codice, nessuna opzione particolare (quindi non selezionando"generate basyc typed composite id", nè "Decect optimistic lock columns", nè "detect many-to-many tables"), e nella schermata exporters, non ho selezionato nessuna delle opzioni in alto (quindi non ho selezionato nè "Use java 5 sintax" nè "Generate EJB3 annotations") e come exporters ho selezionato "domain code" (che genera le classi java che poi utilizzo), "Hibernate xml mapping .hbm.xml" (che genera i file xml per specificare ogni singola classe), "DAO Code" (che a quanto pare genera delle classi java chiamata come le precedenti+home... non so esattamente a cosa siano necessari, pare sempre ad hibernate), sia "Hibernate Xml Configuration, cfg.xml" che genera un nuovo hibernate.cfg.xml con i riferimenti ai file .hbm.xml che vengono generati.

giovedì 7 agosto 2008

JAVA DAO, ORM, POJO

Abbiamo deciso di approfondire lo studio di Hibernate, effettivamente potrebbe esserci molto di aiuto, sia per la normale interrogazione di database (sia in selezione che in salvataggio) sia perché potrebbe evitarci i problemi di compatibilità con i due database che vogliamo supportare: Oracle e SQL Server.

Abbiamo deciso di non affidarci totalmente a GORM (Grails Object Relational Mapping) perchè groovy si rileva meno performante in alcune condizioni, e abbiamo paura che sia limitante nel futuro.

Quindi la scelta ricade sulla creazione di un ORM tramite JAVA DAO (Java Data Access Object) create con delle classi java POJO (Plain Old Java OBject).
Questo significa mappare tutto il nostro database con delle semplici classi java che devvano rispecchiare determinate carrateristiche.
In particolare Hibernate non ha richieste eccessive, ma secondo la logica del convention over configuration, è sempre meglio cercare di rispettare più richieste possibili, tra le quali:

  • Ogni classe dovrebbe avere un suo identificare univoco, chiamato Id (e qui per noi è un problema... perchè in pratica ogni tabella del nostro database ha un id composto da due campi stringa... decisamente lontano dagli standard che prevedono un id numerico autoincrementale... lo so lo so)
  • Ogni classe dovrebbe prevedere un costruttore a zero argomenti, che sarà utilizzato da Hibernate per istanziare la classe
  • Tutti i campi della tabella dovrebbero essere trasformari in campi della classe. Quindi ogni classe dovrebbe avere una serie di campi da considerare persistenti (quindi direttamente mappabilis ul database), preferibilmente da settare come privati, e quindi definire i getter e i setter per ognuno di questi campi. In particolare ogni campo dopvra rispettare le classiche convenzioni ORM, quindi nel caso di un nome campo (o tabella) composto d apiù nomi uniti con l'underscore, si dovrà converire con nome univoco con le lettere maiuscole per ogni parola che lo compone... esempio il campo data_di_nascita sarà convertito in dataDiNascita. Inoltre per convenzione Hibernate si aspetta di trovare i getter e i setter così composti getDataDiNascita e setDataDiNascita.
  • Le classi non dovrebbero essere dichiarate final, o in tal caso caso, dovrebbero implementare un interfaccia che dichiara tutti i metodi pubblici.
  • Nel caso di id composti conviene dichiarare l'id della classe come istanza di un'altra classe, convenzionamente chiamata nomeclasseId, nella quale vengono specificati i singoli campi delal chiave primaria composta.

Ci siamo affidati, per la stesura di queste classid i dominio, ad Hibernate Tool, un plugin per Eclipse appositamente studiato dallo staff di hibernate.
Seguendo i consigli di questa pagina, abbiamo proceduto con questi passi
  • dopo aver installato il plugin per eclipse (semplicemente scompattato lo zip preso dalla pagina di cui supra), ho creato un progetto grails, vuoto, con la classica procedura (nuova directory, grails create-app)
  • Ho messo nella cartella lib del progetto il jar con il driver jdbs del database sqlserver (jtds-1.2.2.jar preso su sourceforge). Avviato eclipse ho importato il progetto appena creato.
  • tasto destro sul progetto, ho creato un nuovo file di configurazione per hibernate: File -> New -> Other -> Hibernate -> Hibernate Configuration File.
    Il file di configurazione l'ho salvato nella directory grails-app/config/hibernate
    Come dialect ho scelto SQL Server, che poi sarà salvato nel file come org.hibernate.dialect.SQLServerDialect
    Come classe del driver ho scelto net.sourceforge.jtds.jdbc.Driver
    Come connection url jdbc:jtds:sqlserver://localhost/Sacci_Gabry;instance=SQLEXPRESS (ho instalato il database in locale)
    Il resto ho lasciato in bianco
  • ancora tasto destro e quindi ho settato al configuarazione della console di Hibernate (File -> New -> Other -> Hibernate -> Hibernate Console Configuration)
    Ho lasciato tutto come proposto, inserendo però nel classpath la lib inserita prima nella directory lib del progetto (il driver jdbc)
  • ancora tasto destro e quindi ho creato un file per il reverse enginering (di fatto quello che poi creerà i file) [File -> New -> Other -> Hibernate -> Hibernate Reverse Engineering File(reveng.xml) ]
    Il file l'ho inserito come prima in grails-app/config/hibernate
    dopo aver selezionato la configurazione e aspettato che il database venisse letto, ho selezionato solo le tabelle del dbo
  • Fatto questo ho fatto partire la compilazione (Lunch -> Hibernate Code Generation -> Open Hibernate Code Generation Dialog)
    Come outpout folder ho scelto src\java, e come nome di package gorm
    Come exporter ho selezionato le domain code, hibernate xml mappings, hibernate xml configuration, e lo Schema Documentation (decisamente opzionale, ma carino, genera della documentazione html interessante e facile da consultae)
    La generazione del codice impiega un po' ad eseguirsi.
  • A questo punto bisogna spostare qualche file per seguire le convenzioni hibernate/grails
    Il file hibernate.cfg.xml appena generato, diverso dal precedente in quanto conteiene tutti i riferimenti ai file di maping, va spostato nella directori config/hibernate, sovrascrivendo quindi il precedente
    Tutti i file hbl.xml vanno spostati nella stessa directorty grails-app/config/hibernate
A questo punto tutto è pronto per lavorare... si possono visualizzare e quindi utilizzare le view di eclipse predisposte per hibernate, consultare il database, la session factory, fare query HQL ecc..