質問

In Core JavaServer Faces we find the following example for deleting rows out of a DataTable, where tableData.names is a list of Name objects:

<h:dataTable value="#{tableData.names}" var="name" ... />    
    <h:commandLink value="Delete" action="#{tableData.deleteRow(name)}" /> 
</h:dataTable>

It comes with a warning that this may not delete the correct row if we use request scope and the list changes "between the rendering of the table and the decoding of the response".

CAUTION: If the value of the data table has request scope, be sure that the data does not change between the rendering of the table and the decoding of the response (page 226 of the 3rd edition)

Can anyone explain that quote in terms of the JSF lifecycle? If "render response" is the final phase in the JSF lifecycle, where does "decoding the response" fit in? Do they mean the decoding of the following postback REQUEST (which sends a generated ID by which to identify the row and hence the name object)?

And: how can we implement this in a more robust fashion?

役に立ちましたか?

解決

The method expression is not evaluated during the request of displaying the form (the encode step as the book is talking about), but during the request of processing the form submit (the decode step as the book is talking about). The inputs and actions of the datatable row are determined on basis of the table's row index. During processing of the form submit, JSF re-iterates over the data model in order to find the submitted values and the invoked actions.

So, if the <h:dataTable value> is tied to a request scoped bean and thus the data model is reinitialized on a per-request basis, then you'll risk the #{item} to actually reference the item at the wrong index during the processing the form submit, because between the requests of displaying the form and submitting the form, the DB might have retrieved a new item, or have removed another item, which would potentially move the desired item to a different index.

To avoid this, the bean needs to be placed in the view scope so that exactly the same datamodel which is initialized in (post)constructor of the initial request will be preserved across postbacks without the need to reinitialize it during the beginning of every single request and thus potentially containing different items or in a different order. The influence is bigger if loading of the datamodel is tied to a specific request parameter under full control of the enduser like a search query.

An alternative, which is actually a bad one in this particular non-idempotent "Delete this item" case, but a good one for the idempotent "Edit this item" case, would be to use a GET link instead. The desired item is immediately rendered as query string parameter of the <a> element.

<h:link value="Edit" outcome="edit">
    <f:param name="id" value="#{item.id}" />
</h:link>
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top