0 Replies Latest reply on Mar 7, 2008 5:24 AM by James Violette

    DataModel change does not always refresh UITable or Trinidad table

    James Violette Newbie

      We have an application that uses Trinidad 1.2.6, Seam 2.0.1 and Hibernate 3.2.


      Based on the following description, we would like to know if there is there an alternative to the default DataModelBinder .


      We have a search page with a summary table. Each row in the summary table links to a detail page where the user may edit that row's data object. Upon save, we raise an event to inform the search page of a change.  The search page @Observer queries the database using Hibernate to reload the data. After Seam processes the events, we use a redirect to return from the detail page to the search page.  We noticed that add, delete and rename actions were showing up in the search page, but field edits were not.


      After some research, we discovered that Seam's Component class, DataModelBinder class and our POJO equals method conspired to keep field edits from showing up in the table.


      Our equals method matches on the POJO's natural id. We are not able to modify our POJO equals method, because it would break Set collection semantics. For example, Set.add(Object) replaces an existing object if the equals method is true, so the equals method must be on the natural key. 


      The Seam DataModelBinder class also uses the equals method to determine if a data model is dirty. Our equals method must return false if any field other than the natural id has changed. According to this test, the data model is not dirty when any non-key fields changed. In fact, the data model is dirty and should drive a refresh action in the UI.


      org.jboss.seam.databinding.DataModelBinder
         public boolean isDirty(DataModel out, 
            javax.faces.model.DataModel wrapper, Object value)
         {
            return !getWrappedData(out, wrapper).equals(value);
         }
      



      The Seam Component class outjects the updated datamodel only if the data model is dirty. The UI table only refreshes when the datamodel is outjected.


      To solve this issue for now, we had to change @DataModel to @Out, which works with Trinidad tables, but not with the plain JSF table.


      org.jboss.seam.Component extends Model
        private void outjectDataModel(Object bean, BijectedAttribute dataModelGetter)
         {
            
            DataBinder wrapper = createWrapper( dataModelGetter.getAnnotation() );
            Object list = dataModelGetter.get(bean);
            String name = dataModelGetter.getName();
            Annotation dataModelAnn = dataModelGetter.getAnnotation();
            ScopeType scope = wrapper.getVariableScope(dataModelAnn);      
            Context context = getOutScope(scope, this).getContext();
            Object existingDataModel = context.get(name);
            
            boolean dirty = existingDataModel == null ||
                  wrapper.isDirty(dataModelAnn, existingDataModel, list);
            boolean reoutject = existingDataModel!=null && scope==PAGE;
            
            if (dirty)
            {
               if ( list!=null )
               {
                  context.set( name, wrapper.wrap(dataModelAnn, list) );
               }
               else
               {
                  context.remove(name);
               }
            }
            else if (reoutject)
            {
               context.set(name, existingDataModel);
            }
               
         }