Newsgroup: it.comp.java
Titolo: Interrogazione via Hibernate di tabelle con foreign key

Salve a tutti.
Sto scrivendo un framework che, per la parte di persistenza fa uso di
Hibernate.
Ho una tabella, che chiameremo Indirizzario, che al suo interno ha uan
foreignk verso la tabella Nazioni.
Ecco il suo hbm (semplificato)
<hibernate-mapping package="mydomain.dao">
	<class name="IndirizzarioDAO" table="ANA_INDIRIZZARIO">
		<id name="id" type="java.math.BigDecimal">
			<column name="ID_IDR" />
		</id>
		<many-to-one name="nazione" 	column="ID_NAZ"/>
	</class>
</hibernate-mapping>
Chiaramente avrò quindi un altro hbm (nazione.hbm) e due classi,
IndirizzarioDAO e NazioneDAO.
In IndirizzarioDAO avrò poi un reference a NazioneDAO.
Facendo una query su IndirizzarioDAO, mi viene automaticamente
popolata anche l'istanza associata.
Quello che vorrei invece automatizzare è il poter fare una query
condizionata con condizioni anche sulle foreign key
In pratica una cose del tipo SELECT * FROM INDIRIZZARIO WHERE ID_NAZ
= ?
Per fare una query condizionata io in pratica uso questo sistema (al
netto di try-catch e controlli di robustezza):
	public List findRecordsByDAO (AbstractDAO abstractDAO) {
		List result = null;
		criteria = session.createCriteria(abstractDAO.getClass());
		Example example = Example.create(abstractDAO);
		example = example.enableLike(MatchMode.ANYWHERE);
		criteria.add(example);
		result = criteria.list();
		return result;
	}
Con questo sistema io riesco a imporre filtri semplicemente impostando
gli attributi del dao in esame.
Il problema è che la classe example non funziona con le foreign key:
in pratica anche se io ho un'istanza NazioneDAO diversa da null dentro
il mio IndirizzarioDAO, la query non la considera.
Affinchè ciò possa avvenire io devo aggiungere una cosa di questo tipo
(dopo criteria.add(example)).
NazioneDAO nazione = ((IndirizzarioDAO) abstractDAO).getNazione();
criteria.add(Restrictions.eq("nazione", nazione));
Così facendo il tutto funziona ma io perdo l'automatismo che invece mi
garantiva la classe Example e che mi permetteva di non dover sapere
quale dao stessi lavorando.
Avete suggerimenti su come estendere l'automatismo alle foreign key?
Qualche particolare attributo sull'hbm ad esempio?
Grazie


non capisco.
tu vuoi rimanere generico e fare una query su un campo del DAO senza
dire di quale campo si tratta ad hibernate? e se hai due manytoone
hibernate cosa dovrebbe fare? instanceof e cosi' via?
non credo si possa fare.
ti potresti scrivere forse un "hql query builder" che prende il nome
della classse che gli passi e fa la query su un campo con un nome
opportunamente specificato.... tipo:
mi passi AbstractDAO che poi e' un NazioneDAO chiamato pippo
nome classe = NazioneDAO
nome parametro su cui filtrare = nazioneDAO
classe this = InirizziarioDAO
quindi genero la query:
select * from IndirizziarioDAO where nazioneDAO =  :par
setParameter("par", pippo)
ovviamente questo ti mette dei vincoli sui nomi dei parametri nelle
classi.

 Grazie
ciao Nicola
--------------------------------
Inviato via 
http://arianna.libero.it/usenet/

 Ciao scusa ma ho capito poco , la query sopra non c'entra nulla ?
Ciao, ritorno, sul mio metodo e spiego meglio il "problema"
Il metodo era questo:
        public List findRecordsByDAO (AbstractDAO abstractDAO) {
                List result = null;
                criteria =
session.createCriteria(abstractDAO.getClass());
                Example example = Example.create(abstractDAO);
                example = example.enableLike(MatchMode.ANYWHERE);
                criteria.add(example);
                result = criteria.list();
                return result;
        }
In un ORM, correggetemi se sbaglio, io lavoro sull'Object ed il mio
"lavoro" si ripercuote sulla base dati attraverso la mappatura
nell'HBM
Per questo motivo, agendo sugli attributi Java del mio DAO, io non
dovrei poi aver bisogno (diciamo in un mondo perfetto) di dover
"scrivere" la query in HQL per poter fare la select su un'unica entità
fisica.
Ed in effetti nel metodo in esame, è così: quel metodo funziona con
qualsiasi tabella solo in base al "tipo" del mio AbstractDAO.
Hibernate vede chi è l'AbstractDAO, verifica con quale tabella è
mappata ed esegue la query.
Il problema si solleva quando la tabella ha delle ForeignKey. Nel mio
AbstractDAO, avrò pertanto un reference ad un altro AbstractDAO (che,
quando eseguo la select viene automaticamente popolato come se avesse
fatto una Join). La mia domanda era come fare ad usare quel referenze
ANCHE per imporre where conditions sulel foreign key visto che l'uso
della classe Example non basta, ossia in pratica per eseguire la query
scritta da n.n SENZA scrivere la query.
Per risolvere la cosa per ora ho implementato questo metodo (che va
invocato prima della chiamata al metodo list())
	private void addRestrictionsOnForeignKey(AbstractDAO abstractDAO)
throws SigemiException{
		ClassMetadata classMetadata =
sessionFactory.getClassMetadata(abstractDAO.getClass());
		String[] propertyNames = classMetadata.getPropertyNames();
		for (String propertyName: propertyNames){
			Type type = classMetadata.getPropertyType(propertyName);
			if (type instanceof ManyToOneType){
				Object value = IntrospectionHelper.getPropertyValue(abstractDAO,
propertyName);
				if (value != null && value.hashCode() !=
AbstractKey.UNDEFINED_HASHCODE){
					criteria.add(Restrictions.eq(propertyName, value));
					SigemiLogger.getLogger().debug("Aggiunta Restriction per
"+abstractDAO.getClass()+" sull'attributo "+propertyName);
				}
			}
		}
	}
Con questo metodo, ora riesco ad eseguire la query di n.n.
L'ultimo problema da risolvere è adesso quello della condizione sulla
tabella associata ma non sul campo chiave;
in pratica, una cosa del tipo
SELECT ind from IndirizzarioDAO ind where ind.nazione.descnazione like
'%pippo%'
Suggerimenti?
Grazie

 Grazie


On 10 Mar, 14:01, 
n...@libero.it
 (n.n) wrote:

Concordo su tutto ciò che hai scritto.
Tuttavia, una buona best practice JAVA è quella di non "diffondere"
stringhe in giro per il codice.
Volente o nolente, il nome di un attributo hbm (anzichè il nome di una
colonna db) rientra nella fattispecie. Una volta che viene cambiato/
eliminato il nome dell'attributo se io mi "dimentico" delle query in
cui viene utilizzato, ho errori a runtime.
Finchè posso lo evito, tanto più che se riesco a scrivere un qualcosa
di riutilizzabile così come ho fatto per le foreign key, il guadagno
si amplifica.