5 Replies Latest reply on Jul 10, 2007 5:46 AM by rapowder

    update DataModel values

    rapowder

      Hi,

      I have a page that shows a table built over a datamodel of items. each item contains a collection of property, each of which represents a column of my table. i.e.

      i.e. a line in my table looks like this:
      id_x | firstname_x | familyname_x

      items can be added/edited from another page. After saving the item, the list is rendered correctly (showing changed properties or new items), but when I edit/create items with two browsers I do not get an update when a property is just changed.

      Scenario:

      - Client1 is on the item list page
      - Client2 modifies item x: "name x" becomes "name y"
      (Client 2 sees the modification on its list)
      - Client1 refreshes its list (values are reloaded from db since the I null the list and the factory method repopulates it), but the name visible in the table is still "name x"

      This does not happen when I create a new item, since after a refresh I can see it on both browsers.

      Do you think this problem could be related to lazy initialization of item collections, and do you have a solution for that?

      Thanx, cheers!

        • 1. Re: update DataModel values
          pmuir

          Show code :)

          • 2. Re: update DataModel values
            rapowder

            Ok, I cleaned up the code to show you what is needed for this problem:

            Here is the bean that shows the item list:

            @Name("itemList")
            @Scope(ScopeType.CONVERSATION)
            @Stateful
            @LoggedIn
            public class MItemListActionBean implements MItemListAction {
            
             @In(create = true, value = "myEM")
             private EntityManager em;
            
             // other stuff...
            
             @DataModel("items")
             private List<Item> items;
            
             @DataModelSelection("items")
             private Item item;
            
             @Begin(join=true)
             @Factory("items")
             public void init() {
             // retrieving
             this.allItems = null;
             this.allItems = getItemsFromDB();
             // sorting
             // etc...
             }
            
             @End
             public String selectItem() {
             return "edit";
             }
            }
            


            The method getItemsFromDB() just queries the db. Note that if a property changes, the query returns the same list than before the modification (the only difference will be an element change in the properties collection inside item).

            Here is the bean to edit an item (I show you this just to show the conversation model):

            @Name("editItem")
            @Scope(ScopeType.CONVERSATION)
            @Stateful
            @LoggedIn
            public class EditItemActionBean implements EditItemAction {
            
             @In(create = true, value = "myEM")
             private EntityManager em;
            
             @Begin(nested=true)
             @Factory("itemPropertyList")
             public void initProperties() {
             if(this.item != null) {
             em.refresh(this.item);
             Set<MProperty> set = item.getProperties();
            
             //put properties in the datamodel that will be shown....
            
             }
            
             // other methods ...
            
             public String saveItem() {
            
             // do some stuff with the properties...
            
             // Ends conversation before redirecting to item list
             Conversation conversation = Conversation.instance();
             log.info("Ending " + conversation.getDescription());
             conversation.end(true);
            
             return "ok";
             }
            
            


            This is the entity class Item:

            @Entity
            @Name("item")
            @Table(name="item")
            public class Item {
            
             @ManyToOne( targetEntity = ItemClass.class )
             @JoinColumn(name = "it_class", nullable = false)
             private ItemClass itemClass;
            
             @ManyToMany
             @org.hibernate.annotations.Fetch(org.hibernate.annotations.FetchMode.SUBSELECT)
             @org.hibernate.annotations.Cascade({
             org.hibernate.annotations.CascadeType.SAVE_UPDATE,
             org.hibernate.annotations.CascadeType.MERGE,
             org.hibernate.annotations.CascadeType.PERSIST})
             @JoinTable(
             name = "item_prop",
             joinColumns = {@JoinColumn(name = "ip_item")},
             inverseJoinColumns = {@JoinColumn(name = "ip_prop")})
             private Set<Property> properties = new HashSet<Property>();
            
             // getters, setters, other stuff...
            }
            


            Here is the jsf that shows the item list:

             <div class="section">
             <h:form id="sc_itemlist">
             <t:dataTable value="#{items}" var="row">
            
             <t:columns value="#{itemList.columnHeaders}" var="columnHeader">
             <f:facet name="header">
             <h:outputText value="#{columnHeader.propertyClassLabel}" />
             </f:facet>
             <!-- triggers iterator to get the next property (property is stored into currentProperty and can be manipulated without triggering the iterator) -->
             <h:inputHidden value="#{row.nextProperty}" />
             <h:outputText value="#{row.currentProperty.typedValue}" converter="OutputTextFieldConverter"/>
             </t:columns>
            
             <h:column>
             <f:facet name="header">
             <h:outputText value="Action"/>
             </f:facet>
             <s:link action="#{itemList.selectItem}" value="Edit"/>
             <h:outputText value=" " />
             <s:link action="#{itemList.deleteItem}" value="Delete"/>
             </h:column>
            
             </t:dataTable>
             </h:form>
             </div>
            


            Hope this code is enough to understand the problem... Thanx!

            • 3. Re: update DataModel values
              pmuir

              How does the list refresh happen?

              • 4. Re: update DataModel values
                rapowder

                One more thing: I actually noticed that if I do an em.refresh(item) on each item before showing the list it works, but I'd like to find another solution since this one is very expensive in time...

                • 5. Re: update DataModel values
                  rapowder

                  Ops, I didn't see your answer...
                  To refresh the list I load again the page from a menu where I can select the type of item to show:

                   <t:dataList layout="unorderedList" value="#{itemClassList}" var="ic">
                   <s:link value="#{ic.label}" action="#{itemClasses.selectItemClass}"/>
                   </t:dataList>
                  


                  where selectItemClass() is just a method that returns the item list page from a stateful bean with scope SESSION:

                   @DataModel("itemClassList")
                   private List<MItemClass> itemClassList;
                  
                   @DataModelSelection("itemClassList")
                   @Out(required=false)
                   private MItemClass itemClass;
                  
                   public String selectItemClass() {
                   return "show_items";
                   }
                  


                  the itemClass is injected in the item list bean..