# [JSF+Hibernate]: DB-Constraints in Validierungsphase?



## Guest (9. Mai 2006)

Nach dem abschicken eines Formulars werden bei JSF ja mehrere Phasen durchlaufen.

Unter anderem sind das "Process Validation", wo die eingebenen Werte auf Korrektheit überprüft werden, und danach irgendwann "Invoke Application", wo Daten z.B. in die Datenbank geschrieben werden können. Während "Process Validation" ist es möglich, eine Fehlermeldung zu generieren, so dass das Formular dem Benutzer nochmals vorgelegt wird. Bei "Invoke Application" geht das nicht mehr.

Ich habe folgenden Fall: Es gibt bei einer Datenbank-Tabelle ein Constraint (in meinem speziellen Beispiel ist das ein UNIQUE Fremdschlüssel, aber das ist nicht so wichtig). Wenn der Benutzer nun eine Eingabe tätigt, die dieses Constraint verletzt, so wird dies erst in der Phase "Invoke Application" von Hibernate bemängelt. Sprich: Der Benutzer bekommt eine unschöne Exception.

Ich möchte nun aber, dass der Benutzer eine Fehlermeldung bekommt (in meinem Fall z.B. "Dieses Dingens wurde bereits einem anderen Dingsbums zugewiesen, Sie müssen ein anderes wählen"), und nochmal das Formular vorgelegt bekommt. Klar, ich könnte einen Validator schreiben, der von Hand in der Datenbank nachprüft, ob irgendwas nicht passen würde. Aber das lehne ich aus zwei Gründen ab:

- es wäre doppelt gemoppelt, und ich programmiere ungern redundant (ist fehleranfällig und mühsam)
- zwischen der Validierung und dem schreiben in die DB könnte ein anderer Benutzer ja etwas verändern, so dass doch noch eine Exception kommt

Gibt es eine Möglichkeit, dass ich die Hibernate-Fehlermeldung irgendwie doch noch verwursten kann und JSF dazu bringen kann, das Formular nochmal vorzulegen? try {...} catch(...) {addMessage(...) } frisst er leider nicht.


----------



## Gumble (9. Mai 2006)

allererstens: hab keine Ahnung.. bin aber interessiert 
wie/wo machst Du den DB Zugriff, bzw. das Schreiben? Da hast Du doch sicher deine eigene API die letztendlich eine HibernateSession verwendet - und dies nutzt Du ein einem Bean? Kann man darin nicht die Exception fangen (trx muss halt gleich comitted werder) und dann ggfs den Fehler z.B als FacesContext.getCurrentInstance().addMessage(..) Fehlermeldung anzeigen lassen? 'RenderResponse' kommt ja erst ganz am Ende.
Die DB-Funktion wirst du ja wohl per 'action' ausloesen - d.h. dann auch dementsprechend 2 Regeln (erfolg, fehler) in der faces-config machen, wobei der Fehlerfall wieder die selbe Seite aufruft.

aber vielleicht denk ich auch zu Trivial...


----------



## Guest (10. Mai 2006)

Ich geh mal fix ins Detail, wie JSF arbeitet. Nachdem der Benutzer ein Formular ausgefüllt hat, werden 6 Phasen durchlaufen:

1. Restore View
Da werden die verwendeten UI-Komponenten (Eingabefelder etc.) intern aufgebaut und Validatoren, Konverter, Listener etc. drangehängt, falls nicht schon geschehen. Im Grunde wird also das JSP vorverarbeitet.

2. Apply Request Values
Hier werden die vom Benutzer eingetragenen Daten zugeordnet. Beispiel: Wenn ein Benutzer in ein Eingabefeld was eintippt, so wird der Wert hier dann für die weitere Verarbeitung gemerkt.
_Hier können schon Fehlermeldungen generiert werden._

3. Process Validations
Hier wird für jede Komponente (Eingabefeld, Datumsfeld, Checkbox,...) geprüft, ob der vom Benutzer übergebene Wert stimmig ist. Z.B. ist der 35.13.2006 kein gültiges Datum, und dann würde das zugehörige Datumsfeld als ungültig gekennzeichnet werden. Außerdem werden noch Konvertierungen durchgeführt (z.B. Datum im Format dd.mm.jjjj wird in java.lang.Date umgewandelt, oder ein String "1234" in eine Ganzzahl).
_Jedenfalls kann man auch hier Fehlermeldungen generieren._

4. Update Model Values
Die eingetippten Daten werden dem zugehörigen Datenmodell übergeben. z.B. eine Bean namens "Person" wird mit setVorname(WertDerVornamenEingabefeldes) oder setGeburtsdatum(WertDesDatumsFeldes) befüllt.
_Auch hier können noch Fehlermeldungen generiert werden._

5. Invoke Application
Hier wird die Geschäftslogik ausgeführt - also das was unter action="{eineBean.eineMethode}" steht.
In meinem Fall würde man hier das Bean "Person" mittels Spring-Hibernate-Template (wasn Wort *g*) in der Datenbank gespeichert.

Und wenn HIER jetzt ein Fehler passiert, kann ich keine Fehlermeldung mehr generieren. JSF haut einem dann was um die Ohren. Ich kann zwar die Datenbank-Exception fangen und ggf. ein Outcome nosuccess oder so generieren. Aber dummerweise kommt direkt danach noch eine Exception, die ich nicht fangen kann, und die den gesammten Vorgang abbricht: "javax.servlet.ServletException: Error calling action method of component with id personForm:save" (hier sei gesagt, dass das Ding normalerweise funktioniert, die Exception kommt wirklich nur, wenn ein Datenbankfehler auftritt).

6. Render Response
Und hier erfolgt die Ausgabe. Entweder wird das Formular nochmals vorgelegt (falls eine Fehlermeldung in Phase 2-4 erzeugt wurde), oder man kommt zu einer anderen Seite (je nach Outcome).


----------



## Guest (10. Mai 2006)

Ok, Leute, vergesst die zweite Exception. Da hab ich nen Fehler gemacht (hatte mit den Resource Bundles zu tun, also wie ne Meldung heißt).

Jedenfalls: ES GEHT DOCH. Man kann Fehlermledungen generieren, auch in Phase 5.

Jetzt muss ich nur noch überlegen, wie ich aus den kryptischen Hibernate-Exceptions ne hübsche passende Fehlermeldung generiere. Z.B. "Diese Frau steht bereits mit einem anderen Mann in Relation Ehe, bitte wählen Sie eine andere" .


----------



## Gumble (10. Mai 2006)

workaround: polygamie


----------

