JSF Lässt sich die Reihenfolge der Ausführung von RequestScoped Services festlegen?

membersound

Bekanntes Mitglied
Hallo,

ich habe folgendes Problem mit dem Updaten von zwei dataTable (Primefaces, aber das sollte egal sein):

-die zweite Tabelle baut auf der ersten auf: die erste zeigt alle Personen, die zweite die zugehörigen Payments für eine selektierte Person.
Außerdem (und das ist der Knackpunkt) soll die erste Tabelle für jede Person die Anzahl der Payments anzeigen. Sofort, wenn eines hinzugefügt wurde.
-ich lasse beide Tables über ein ajax autoUpdate aktualisieren
-habe 2 @RequestScoped Services, welche jeweils in einer @PostConstruct Methode die list-variable für die Tables setzen. Dafür wird innerhalb der PostConstruct Methode ein database query gemacht.

Ich füge nun bei der unteren Tabelle ein Payment ein (mit commandButton und action). Das Payment erscheint sofort in der unteren Tabelle, in der oberen Person-Tabelle wird allerdings die Anzahl der Payments NICHT geupdatet.

Die Ursache konnte ich zumindest identifizieren: auf den buttonclick läuft zunächst der ServicePerson der ersten Tabelle los, und dann erst der ServicePayment mit der Action Methode der zweiten Tabelle! Das hat zur Folge, dass zunächst die erste Tabelle NICHT aktualisiert wird, sondern nur die zweite.
Erst beim nächsten Request wird dann die erste Tabelle auch aktualisiert.

Das liegt offenbar daran, dass wie beschrieben zunächst der Service für die erste Tabelle läuft (damit die alten Daten aus der DB holt), und dann erst die eigentliche Action Methode des Buttons (wodurch nun erst das neue Payment in der DB drin ist).


Jetzt ist die Frage: das kann doch nicht gewollt sein? Oder kann ich irgendwas übersehen haben?

Ich kann es nicht beides in einen Service packen, weil das sonst zu unübersichtlich wird.
Jetzt ist also die Frage: wie kann die die Reihenfolge der Services steuern? Und warum wird überhaupt der ServicePerson zuerst ausgeführt, wenn ich einen Button clicke, der eine Action für einen ganz anderen Service, nämlich ServicePayment, definiert?


Danke falls jemand soweit gelesen hat...


Pseudocode in etwa so:

JSF:
[XML]<outputPanel autoUpdate=true>
<dataTable value=servicePerson.list>
<column> #{var.list.size()}
<command button addPerson>
</outputPanel>

...

<outputPanel autoUpdate=true>
<dataTable value=servicePayment.list>
<commandButton addPayment>
</outputPanel>[/XML]


SERVICES:

Java:
class ServicePerson {
	private list;
	
	@PostConstruct
	findAll() {
		list = NamedQuery("Person.ALL")
	}
	
}

class ServicePayment {
	private list;
	
	@PostConstruct
	findAll() {
		list = NamedQuery("Payments.ALL_FROM_CUSTOMER")

		/* wenn ich hier den database request wie in ServicePayment 
		 * machen würde, dann bekomme ich hier die korrekte anzahl! 
		 * dh ich muss es nur hinbekommen, dass ServicePerson NACH ServicePayment läuft.
		 */
		log(NamedQuery("Person.ALL").size())
	}
	addPayment() {
		persist...
	}
}

------------

Also Workaround fiel mir grad noch ein:
Ich kann natürlich ServicePerson IN ServicePayment injezieren, und nach dem persistieren des Payments innerhalb einfach nochmal die findAll() Methode des ServicePerson aufrufen. Damit dann auch der aktuelle Stand der DB gefetcht wird:
Java:
class ServicePayment {
	@Inject
	ServicePerson

	addPayment() {
		persist...

		ServicePerson.findAll();
	}
}

Aber das kann nicht die Lösung sein, unschöner gehts wohl kaum...
 
Zuletzt bearbeitet:
S

Sym

Gast
Du könntest Deinem Button ein ajax request zum Neuzeichnen der oberen Tabelle mitgeben. Dann sollte das klappen.
 

membersound

Bekanntes Mitglied
Das Problem ist, dass die Tabellen beiden in einer eigenen xhtml sind. Dh ich komm vom Button aus nicht an die id's der ersten Tabelle. Deshalb steht die ja auch im autoUpdate...

Müsste nicht auch ein bloßes <p:commandButton><p:ajax /></p:commandButton> funktionieren? Ändert aber leider nichts am Verhalten.


Ich frag mich ja gerade, ob ich meine Services nicht einfac @SessionScoped geben soll? Damit funktioniert es auf jeden Fall, und ich umgehe gleichzeitig die Probleme mit LazyLoading...
 
Zuletzt bearbeitet:
S

Sym

Gast
Ich kenne nicht genau die Attribute vom Primefaces-Ajax, aber Du solltest dort angeben, was Du neu zeichnen möchtest. Die Id der anderen Tabelle hast Du doch, oder? Wenn ich Dich richtig verstanden habe, sind die Tabellen doch untereinander, oder?
 

membersound

Bekanntes Mitglied
Ja, aber jede Tabelle in einer einzelnen xhtml, und eingebunden in einer gemeinsamen mit <ui:include src=...> untereinander.
Somit hat aber die eine xhtml keine Ahnung von den id's der anderen...
Naja, vielleicht muss ich doch alle in eine packen.
 
S

Sym

Gast
Nein, musst Du nicht. Wenn die Tabelle eine eindeutige Id hat, kannst Du diese in Deinem Ajax-Call auch nutzen. Egal, in welchem Template die eigentliche Komponente hängt.
 

membersound

Bekanntes Mitglied
Nein kann ich eben nicht :/

Ich poste mal kurz meine Tags, vl ist ja irgendwo noch ein Fehler drin?

Java:
//personTable.xhtml
<p:outputPanel autoUpdate="true">
		<h:panelGrid columns="2">
			<h:form>
				<p:dataTable id="dataTablePerson">
	

//closing tags


//paymentTable.xhtml
<p:outputPanel autoUpdate="true">
		<p:outputPanel rendered="#{not empty tableManager.selectedPerson}">
			<h:panelGrid columns="2">
				<h:form id="formPayment">
					<p:panel>
						<p:commandButton action="#{service.createNewPayment()}"
							value="Create" update=":dataTablePerson" />
//closing tags

Code:
javax.servlet.ServletException: Cannot find component with identifier ":dataTablePerson" in view.
	javax.faces.webapp.FacesServlet.service(FacesServlet.java:606)
	org.jboss.weld.servlet.ConversationPropagationFilter.doFilter(ConversationPropagationFilter.java:67)

alternative mit ajax (aber eigentlich besitzt der p:commandButton bereits ein ajax event):
Java:
<p:commandButton action="#{service.createNewPayment()}"
							value="Create"><p:ajax  update=":dataTablePerson"/></p:commandButton>
Code:
17:06:07,067 Schwerwiegend [javax.enterprise.resource.webcontainer.jsf.context] (http--127.0.0.1-8080-2) javax.faces.FacesException: Cannot find component with identifier ":dataTablePerson" in view.

Ratlos.
 

JimPanse

Bekanntes Mitglied
ich glaube bei Primefaces konnte die clientId nicht richtig aufgelöst werden wenn der NamingContainer (die Form) eine
präfix id an die Child-Komponenten ranhängt.

Java:
<h:form prependId="false>

...

das könnte helfen.
 

membersound

Bekanntes Mitglied
Leider hilft prependId auch nicht...

2 Forms funktionieren aber prinzipiell schon. Zumindest mit Hilfe des Workarounds in meinem Eingangsposting.
Ist halt nur echt sehr unschön...
 
S

Sym

Gast
Warum packst Du nicht einfach alles mal in eine Form und schaust, ob es dann mit dem Neuzeichnen funktioniert?

2 Forms auf einer Seite sind immer unschön.
 

Ähnliche Java Themen

Neue Themen


Oben