简体   繁体   English

为什么在从数据库加载辅助bean中的新数据后不更新jsf视图?

[英]Why the jsf view is not updated after new data in the backing bean are loaded from database?

I am - unfortunally - working with jsf and I am experiencing a problem. 我 - 不幸的是 - 与jsf一起工作,我遇到了一个问题。 I have a jsf page that displays a table with some data, using the <h:dataTable> component. 我有一个jsf页面,使用<h:dataTable>组件显示包含一些数据的表。 Every row of this table has an <h:commandLink> with a Remove action to remove the item in that row. 该表的每一行都有一个带有删除操作的<h:commandLink> ,用于删除该行中的项目。 When I perform that action, the method in the backing bean is correctly called, the ArrayList that contains the table items is correctly uptaded, and the navigation method to come back in the same page where the table is, is correctly performed. 当我执行该操作时,正确调用了辅助bean中的方法,正确地使用包含表项的ArrayList ,并且正确执行了返回到表所在的同一页面的导航方法。

But when the page is reloaded the table is not updated . 但是当重新加载页面时,表格不会更新 I see the same items that were in the table before the remove action. 我在删除操作之前看到了表中的相同项目。

If I reload again the page, now the table is updated. 如果我再次重新加载页面,现在表格已更新。

It seems just like the view is rendered before that the backing bean has completed its updates. 看起来就像在支持bean完成更新之前呈现的视图一样。

How can I force to render the view just when the backing bean has completed its updates? 如何在支持bean完成更新时强制呈现视图?

Here some code: 这里有一些代码:

The commandLink in the jsf page, inside the dataTable: jsf页面中的commandLink,在dataTable中:

<h:column>
<f:facet name="header">
    <h:outputText value="Rimuovi" />
</f:facet>
<h:commandLink action="#{servicesListBean.removeServizio}" title="Rimuovi questo servizio" onclick="if(!confirm('Vuoi davvero rimuovere questo servizio?')) return false">
    <h:outputText value="Rimuovi" />
</h:commandLink>
</h:column>

And here the method in the backing bean: 这里是支持bean中的方法:

public String removeServizio() {
        this.servizioToRemove = (Servizio) getDataTable().getRowData();
        try {
        ServiziDAO.removeServizio(this.servizioToRemove.getId());
        } catch (Exception e) {
            // ...
        }

        return userSessionBean.goToElencoServizi(); 
    }

In this case, I gave request scope to the backing bean. 在这种情况下,我将请求范围提供给了支持bean。 I already tried to give it session scope and call a method to update the list, but the result is the same. 我已经尝试给它会话范围并调用一个方法来更新列表,但结果是一样的。

I hope I was clear enough. 我希望我很清楚。 Thanks to everyone in advance. 感谢大家提前。


UPDATE TO THIS QUESTION THAT CHANGES EVERYTHING 对这个改变一切的问题的更新

Thanks to everyone. 谢谢大家。 As McDowell said, the problem was not in the time when view was rendered, and the problem was not JSF related at all. 正如McDowell所说,问题不是在呈现视图的时候,问题根本不是JSF相关的。

What happened is that when I removed an item from the DB, I did not delete the row, I just set an end date to the item. 发生的事情是,当我从数据库中删除一个项目时,我没有删除该行,我只是为该项目设置了结束日期。 This is the right way to do it in my application, but while in the query that setted the end date to the item I took the time using System.currentTimiMillis() , in the query that reloaded the uptaded list I used the sysdate of the Oracle server. 这是在我的应用程序中执行此操作的正确方法,但是在查询中将结束日期设置为项目时我使用System.currentTimiMillis() ,在重新加载uptaded列表的查询中,我使用了sysdate Oracle服务器。

There are some fractions of second of difference between this two dates, and that's why I could see the updated list just when I reloaded the page: because one ore two second were passed! 这两个日期之间存在一些差异,这就是我重新加载页面时可以看到更新列表的原因:因为一两秒钟就过去了!

Maybe this issue can be useful to someone else. 也许这个问题对其他人有用。

It seems just like the view is rendered before that the backing bean has completed its updates. 看起来就像在支持bean完成更新之前呈现的视图一样。

The only way this could happen is if you did the work in another thread - but it doesn't look like you are doing that. 这可能发生的唯一方法是,如果你在另一个线程中完成了工作 - 但它看起来并不像你那样做。

I am guessing, but it looks like a logic problem in your backing bean. 我猜,但它看起来像你的支持bean中的逻辑问题。 Is your servicesListBean keeping state? 你的servicesListBean保持状态吗? That is: 那是:

  1. HTTP POST HTTP POST
  2. The RESTORE VIEW phase of the lifecycle causes servicesListBean to be created in the request scope (each phase of the lifecycle needs to iterate over every row) 生命周期的RESTORE VIEW阶段导致在请求范围内创建servicesListBean (生命周期的每个阶段都需要迭代每一行)
  3. servicesListBean fetches the rows from the persistence store and they are cached in the bean state servicesListBean从持久性存储中获取行,并以bean状态缓存它们
  4. When we get to the INVOKE APPLICATION phase, removeServizio() removes the target row from the persistence store, but does not do anything about the cached bean state 当我们进入INVOKE APPLICATION阶段时, removeServizio()从持久性存储中删除目标行,但是对缓存的bean状态没有任何作用
  5. The RENDER RESPONSE phase renders the stale cached bean state RENDER RESPONSE阶段呈现过时的缓存bean状态
  6. If you refresh now, the bean gets recreated with new cached values and you see the correct state 如果现在刷新,则会使用新的缓存值重新创建bean,并且您会看到正确的状态

This backing bean recreates the problem: 这个支持bean重新创建了这个问题:

public class DeleteFromRowBean {

  private ListDataModel dataModel;

  public DataModel getList() {
    if (dataModel == null) {
      List<RowBean> list = PersistenceStore.fetch();
      dataModel = new ListDataModel(list);
    }
    return dataModel;
  }

  public String deleteCurrentRow() {
    if (dataModel == null) {
      throw new IllegalStateException();
    }
    RowBean row = (RowBean) dataModel.getRowData();
    PersistenceStore.delete(row.getId());
    return null; // no navigation required
  }

}

Modifying the list while the data table is iterating over it is not a good idea (you'll get concurrent modification exceptions). 在数据表迭代时修改列表不是一个好主意(您将获得并发修改异常)。 The easiest solution in my sample bean is just to release the reference to the cached data. 我的示例bean中最简单的解决方案就是释放对缓存数据的引用。 The data table already has a reference to this for the duration of the iteration in the INVOKE APPLICATION phase; INVOKE APPLICATION阶段的迭代期间,数据表已经对此进行了引用; when the RENDER RESPONSE starts, the data table will call getList() again, causing the new state to be fetched from the persistence store. RENDER RESPONSE启动时,数据表将再次调用getList() ,从而导致从持久性存储中获取新状态。

public class DeleteFromRowBean {

  private ListDataModel dataModel;

  public DataModel getList() {
    if (dataModel == null) {
      List<RowBean> list = PersistenceStore.fetch();
      dataModel = new ListDataModel(list);
    }
    return dataModel;
  }

  public String deleteCurrentRow() {
    if (dataModel == null) {
      throw new IllegalStateException();
    }
    RowBean row = (RowBean) dataModel.getRowData();
    PersistenceStore.delete(row.getId());
    // flush cached data
    dataModel = null;
    return null; // no navigation required
  }

}

If you don't explicitly redirect to "another" page (even if it's the same page), you will get old data. 如果您没有明确重定向到“另一个”页面(即使它是同一页面),您将获得旧数据。 It's feature. 这是功能。 Try something like: 尝试类似的东西:

public String removeServizio() {
    .
    .
    .
    userSessionBean.goToElencoServizi(); // if this redirects to needed page
    return null;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM