PDA

View Full Version : [Richfaces/Hibernate]Inserimento Foreign Keys


John1905
04-11-2010, 10:59
Salve a tutti, questo è il mio primo post nel forum.

Vi spiego subito il mio problema.

Stò sviluppando un'applicazione web che utilizza Tomcat 7, MySql 5, Hibernate 3, jsf 1.2 e Richfaces 3.3.3.

Devo creare una pagina che fà un semplice inserimento di un nuovo record in una tabella. Questa tabella, Sottoconto, contiene una Foreign Keys chiamata idConto collegata al'id(un intero) di un'altra tabella, Conto.

Ora, nei file di Hibernate, più precisamente Sottoconto.java, questa chiave è dichiarata come private Conto conto quindi di tipo conto.

Questo è il form di inserimento:
<h:form id="nuovoSottocontoForm">

<div class="divForm">
<div class="leftDivForm">Conto</div>
<div class="rightDivForm">
<h:inputText id="conto" value="#{sottocontoBean.conto }"/>
<rich:suggestionbox for="conto" var="varConto" suggestionAction="#{contoBean.autocomplete}">
<h:column>
<h:outputText value="#{varConto.descrizione}"/>
</h:column>
</rich:suggestionbox>
</div>
</div>
<div class="divForm">
<div class="leftDivForm">Descrizione</div>
<div class="rightDivForm"><h:inputText id="descrizione" value="#{sottocontoBean.descrizione }"/></div>
</div>
<div class="divForm">
<div class="leftDivForm">Sigla</div>
<div class="rightDivForm"><h:inputText id="sigla" value="#{sottocontoBean.sigla }"/></div>
</div>
<br class="brNew"/>
<div class="center-align">
<a4j:commandButton type="submit" value="Salva" action="#{sottocontoBean.newSottoconto }" >
</a4j:commandButton>
</div>

</h:form>

Conto grazie al suggestionBox raccoglie i valori dal db ed effettua l'autocomplete, i dati vengono poi passati alla funzione newSottoconto presente in sottocontoBean.


public String newSottoconto() {
Session session = HibernateUtil.getSessionFactory().getCurrentSession();
Transaction t = session.beginTransaction();
try {
Sottoconto b = new Sottoconto();
Conto conto;
conto=getConto();
b.setConto();
String descrizione;
descrizione=getDescrizione();
b.setDescrizione(descrizione);
String sigla;
sigla=getSigla();
b.setSigla(sigla);
session.persist(b);
t.commit();
//session.close();
//this.getRisultati();
} catch (Exception e) {
e.printStackTrace();
}
return "success";
}


Il problema è che inputText passa alla funzione una stringa mentre per l'inserimento è necessario un oggetto di tipo Conto.

Non sò se c'è un metodo per passare alla funzione un oggetto di tipo conto(ho provato sia con setPropertyActionListener sia con Param senza risultati) oppurese si può gestire la cosa direttamente nella funzione.
Avevo pensato anche a fare una query facendo una ricerca avendo come base la stringa(lo avevo fatto in jsp ed effettivamente funzionava) però visto che poi avrei altre tabelle con un numero maggiore di chiavi esterne ho paura che la cosa con molti record diventerebbe eccessivamente pesante.

Spero di essere stato sufficientemente chiaro, grazie in anticipo.

javacomelava
04-11-2010, 11:49
Se ho capito bene:

L'utente inserisce in questa tabella delle informazioni relative ad un "Sottoconto" che (a livello di db) è in relazione (figlia) di una entità Conto.
La relazione è realizzata attrverso foreign key formata dall'id del conto sulla tabella sottoconto.

Supponendo che a questo punto dell'elaborazione (ovvero quando mostri questa tabella)tu conosca il CONTO a cui l'utente si sta riferendo,o meglio,la sua primary key(mi sembra difficile pensare il contrario,perchè significherebbe che non hai per niente chiaro il dominio dell'appliczione che stai costruendo),nel metodo del service (newSottoconto) come prima operazione dovrai effettuare una query che ti recupara l'entità CONTO attraverso la sua primary key che conosci. Quindi creare un nuovo SOTTOCONTO,settargli dentro il CONTO recuparato precedentemente e quindi effettuare l'INSERT del SOTTOCONTO creato.

P.s.: Un consiglio che mi sento di darti è:
Dai dei nomi comprensibili alle variabili e ai metodi,perchè cosi come stai facendo rendi il codice inleggibile sia per te (tra 15giorni) che per gli altri!

Comunque in pseudocodice quello che devi fare è:



public String creaSottocontoService(Integer idConto){
Conto conto = HibernateService.findConto(idConto);
Sottoconto sottoconto = new Sottoconto();
sottoconto.setParametro(x);
sottoconto.setParametro(y);
...........
...........

/* Qui setti la relazione tra conto e sottoconto */
sottoconto.setConto(conto);
HibernateService.inserisciSottoconto(sottoconto);
return "success";
}



Ciao

John1905
04-11-2010, 12:06
Ho già provato con la query, passandogli direttamente l'id invece della descrizione e funziona.
Soltanto se per ora è perfettamente fattibile ho paura che andando avanti nel progetto(avrà tabelle con un buon numero di chiavi esterne che fanno riferimento a tabelle con un notevole numero di record) ho paura la cosa diventi pesante.

Speravo ci fosse un modo di passare direttamente l'oggetto dal form(varConto) alla funzione ma sembra che l'unico modo fattibile sia con la query.

Comunque passando ad altro, con varConto.idConto recupero l'id all'interno del suggestion box, se aggiungo un <h:outputText value="#{varConto.idConto}"/>
lo stampa correttamente. A questo punto avrei il problema di dover comunque visualizzare la descrizione nell'inputText ma di dover passare alla funzione l'id. C'è modo di passare un valore che non sia quello scritto sull'inputText?

Grazie mille.

javacomelava
04-11-2010, 13:29
Non credo di aver capito bene cosa vuoi fare,prova a spiegarti meglio.

come fai a valorizzare la variabile DESCRIZIONE di CONTO se ancora non hai un CONTO???

L'idConto ti viene visualizzato perchè (immagino) l'AJAX BRIDGE di richfaces,attraverso un partial submit,valorizza automaticamente la variabile idConto del relativo managed bean(quando scrivi nella suggestion box,che immagino sia collegata ad una variabile sul managed bean contenente una collezione di idConto validi).

Per avere la descrizione del conto:

In qualche modo,quando arrivi a caricare la pagina .jspx in questione ( e quindi viene creato il relativo managed bean) devi già avere il CONTO di cui vuoi la descrizione,caricato:

Va effettua quindi una query che ti valorizza le variabili relative al conto sul manged bean (richiamando ad esempio il service adibito al recupero di un CONTO nel costruttore del managed bean).A questo punto avresti tutte le informazioni relative ad un conto,compresa la descrizione. Per arrivare a ciò devi gia possedere l'id del conto da caricare.

Quindi:

Nel Managed Bean:



public class InserimentoSottocontoBean {

......
......
private Conto conto;

public InserimentoSottocontoBean(){
/* Recuperi il cono in fase di creazione del bean */
conto = HibernateService.recuperaConto(idConto);
.........
.........
}

public Conto getConto(){
return this.conto;
}

public void setConto(Conto conto){
this.conto=conto;
}

/* cambia nome a questo metodo ti prego,chiamalo inserisciSottoconto :-)))))) */
public String newSottoconto(Integer idConto){
..........
..........
..........
}


}



nella .jspx



................
<h:outputLabel value="Descrizione Conto" />
<h:outputText value="inserimentoSottocontoBean.conto.descrizione" />
..............



Ovviamente quell'inputText dove dovresti inserire l'id del conto è anomala,in quanto in questo caso si presuppone che tu gia sappia l'ide del conto da caricare (dato che il caricamento del CONTO avviene in fase di creazione del ManagedBean).

Per ovviare a questa problema:

1. dividi in pagine e in manged bean diversi quelli relativi a "Richiesta conto" e "Inserimento Sottoconto"

2. li utilizzi nella stessa pagina jspx,ma in due managed bean diversi, utlizzando l'attibuto RENDERED su dei panelGroup in modo appropriato (renderizzi il pannello contentene i dati del conto solo dopo aver valorizzato l'idConto ----> il manged bean di "descrizione conto" viene creato solo quando avviene l'effettiva renderizzazione)

John1905
04-11-2010, 16:08
Allora, ti spiego meglio.

suggestionAction richiama la funzione public List<Conto> autocomplete{...} che richiama a sua volta una query che restituisce tutti i record della tabella Conto.
Quindi varConto contiene una lista di tutti i record presenti nella tabella Conto, infatti con varConto.idConto, varConto.descrizione e varConto.sigla richiamo i vari campi(nell'esempio che ti ho postato quando scrivo nell'inputText si apre il menù a tendina con tutte le descrizioni).

L'oggetto all'interno della pagina quindi credo ci sia il problema è che inputText ed outputText non interagiscono con l'oggetto(quindi quando seleziono una descrizione dalla lista lui si limita a copiarmi l'outputText nell'input text senza effettivamente "scegliere" l'oggetto come può accadere con un comboBox).

A questo punto potrei semplicemente passare la stringa con la descrizione a inserimentoSottoconto e fare la query in base alla descrizione invece che in base all'id(descrizione è comunque un valore univoco).
Oppure potrei provare a implementare un comboBox(non sò di preciso come funzionano in Richfaces e se sia possibile implementarci l'autocomplete ma in php questa cosa l'ho già fatta...)

Ora faccio un pò di prove, grazie ancora.

javacomelava
04-11-2010, 16:22
Immagino quindi che quando hai scelto un "CONTO" tramite l'autosuggestion questo venga memorizzato in una variabile di tipo Conto (sul managed bean). Se è cosi non capisco dove sta il problema....hai tutto in quella variabile:



List<Conto> autocomplete();



e poi qualcosa del tipo:



Conto selectedConto;



dove viene memorizzato il Conto selezionato.


Non so se l'autosuggestion funziona cosi' (non credo,ma puoi comunque arrivarci a farglielo fare tipo con javascript smagheggiando un pò)

Le combobox funzionano proprio nel modo che ti ho descritto.

Hanno una lista che rappresenta le OPTIONS e una variabile che rappresenta il valore SELECTED.

John1905
04-11-2010, 17:01
Credo che il problema sia che in questo modo, con inputText ed outputText, non và a selezionare effettivamente l'oggetto come avviene in un comboBox ma si limita a copiare l'outputText nell'inputText.

A questo punto provo il comboBox, in alternativa vedo di inventarmi qualcosa in javascript.

javacomelava
04-11-2010, 20:16
Si,direi che la combobox è la naturale soluzione al tuo problema ;)