2 Replies Latest reply on Jun 8, 2010 2:58 PM by andreea

    Persistence problems

    andreea

      I'm pretty much new to all things Seam, so please have mercy and help me with this one.
      I'm using JBoss Seam 2.2 and JBoss Application Server 5.1.0.


      This is the scenario:


      I've got TestCases and TestSteps. One TestCase has multiple TestSteps.
      I have a table that displays the steps and actions like addStep and deleteStep.


      I use rich:inplaceInput to edit existing steps. This works perfectly.


      Adding or deleting a step however does not. When adding, I create an empty step which is displayed in the table and the user can then edit it.


      I can't explain how it persists changes to existing steps, but doesn't cooperate when list TestCaseHome.testSteps changes in size.


      Entity TestStep:




      @Entity
      @Table(name = "teststeps")
      public class TestStep implements java.io.Serializable {
      
           private static final long serialVersionUID = 6534546556882292702L;
           private long id;
           private TestCase testCase;
           private String test;
           private String expectedResult;
           private long ordering;
           [...]
           @ManyToOne(fetch = FetchType.LAZY)
           @JoinColumn(name = "tc_id")
           public TestCase getTestCase() {
                return this.testCase;
           }
           public void setTestCase(TestCase testCase) {
                this.testCase = testCase;
           }
           [...]
      }



      Entity TestCase:
      Entity CoreTestObject isn't really relevant, TestCase just inherits it's id from it.



      @Entity
      @Table(name = "testcases")
      @PrimaryKeyJoinColumn(name="id")
      public class TestCase extends CoreTestObject implements java.io.Serializable{     
           [...]
           private Set<TestStep> testSteps = new HashSet<TestStep>(0);
           public TestCase(Set<TestStep> testSteps, ...) {
                [...]
                this.testSteps = testSteps;
           }
           [...]
           @OneToMany(fetch = FetchType.LAZY, mappedBy = "testCase")
           @OrderBy("test")
           public Set<TestStep> getTestSteps() {
                return this.testSteps;
           }
      
           public void setTestSteps(Set<TestStep> testSteps) {
                this.testSteps = testSteps;
           }
      }



      TestCaseHome:




      @Name("testCaseHome")
      @Scope(ScopeType.CONVERSATION)
      public class TestCaseHome extends EntityHome<TestCase> {     
           @DataModel
           private List<TestStep> testSteps;
           [...]
      
           /*@param step The Step after which the new Step is to be inserted*/
           public void addStep(TestStep step){
                testSteps = new ArrayList<TestStep>(this.getInstance().getTestSteps());
                long id, ordering;
                [...] // here I find the id and ordering of step
                testSteps.add(new TestStep(id+1, this.getInstance(), "", "", ordering+1));     
                this.getInstance().setTestSteps(new HashSet<TestStep>(testSteps));
           }
           
           /*@param step The Step to be deleted*/
           public void deleteStep(TestStep step){
                int index = testSteps.indexOf(step);          
                testSteps.remove(index);
                this.getInstance().setTestSteps(new HashSet<TestStep>(testSteps));          
           }
      }





      EntityHome:


      public class EntityHome<E> extends Home<EntityManager, E>
      {
         @Transactional
         public String update()
         {
            joinTransaction();
            getEntityManager().flush();
            updatedMessage();
            raiseAfterTransactionSuccessEvent();
            return "updated";
         }  
         @Transactional
         public String persist()
         {
            getEntityManager().persist( getInstance() );
            getEntityManager().flush();
            assignId( PersistenceProvider.instance().getId( getInstance(), getEntityManager() ) );
            createdMessage();
            raiseAfterTransactionSuccessEvent();
            return "persisted";
         }
         [...]
      }





      View:


      <rich:dataTable value="#{testCaseHome.testSteps}" var="_testStep"
                id="testStepsTable" rowKeyVar="row" autoresize="true">
           <rich:column sortBy="#{_testStep.ordering}"
                sortOrder="ASCENDING" style=" width : 20px;">
                <f:facet name="header">Order</f:facet>
                <rich:inplaceInput layout="block" value="#{_testStep.ordering}"
                     selectOnEdit="true" editEvent="onclick">
                     <a:support event="onviewactivated" ajaxSingle="true"
                          reRender="testStepsTable" />
                </rich:inplaceInput>
           </rich:column>
      
           <rich:column sortBy="#{_testStep.expectedResult}" [...] </rich:column>     
      
           <rich:column sortBy="#{_testStep.test}"> [...] </rich:column>
                                              
           <rich:column style=" width : 80px;">
                <f:facet name="header">
                     Action
                          </f:facet>
      
                <a:commandLink ajaxSingle="true" id="deletelink"
                     reRender="testStepsTable"
                     action="#{testCaseHome.deleteStep(_testStep)}">
                     <h:graphicImage value="/img/delete.gif" />
                     <f:param name="testCaseId" value="#{testCaseHome.instance.id}" />
                     <f:param name="testStepFrom" value="TestCase" />
                </a:commandLink>
      
                <a:commandLink ajaxSingle="true" id="addlink"
                     reRender="testStepsTable"
                     action="#{testCaseHome.addStep(_testStep)}">
                     <h:graphicImage value="/img/plus_icon.gif" style=" width : 16px; height : 16px;"/>
                     <f:param name="testCaseId" value="#{testCaseHome.instance.id}" />
                     <f:param name="testStepFrom" value="TestCase" />
                     <s:conversationId />     <!-- <<<<I thought that might help but it didn't-->
                </a:commandLink>
           </rich:column>
      </rich:dataTable>
      [...]
      <div class="actionButtons">
           <h:commandButton id="save"
                value="Save" action="#{testCaseHome.persist}"
                disabled="#{!testCaseHome.wired}"
                rendered="#{!testCaseHome.managed}" /> 
           <h:commandButton id="update"
                value="Save" action="#{testCaseHome.update}"
                rendered="#{testCaseHome.managed}" /> 
           [...]
      </div>
      



      I had to cut a lot from the code, I hope I didn't leave anything relevant out.
      I also hope this is the right place for this question, excuse me if not (noob here).


      I would very much appreciate your help since I'm trying to fix this for weeks.
      Thank you!

        • 1. Re: Persistence problems
          lvdberg

          Hi,


          I am trying to understand what you're doing and also hope you didn't write the EhntiTyHome classes but you're using the one as provide by Seam. The thing I am missing is the action which starts it all and kicks-off the conversation which is needed in these kind of scenarios.
          You must have a conversation started somewhere. In page.xml or in the actionBean.


          Something else you should add is cascading to you entity-classes. If you want to have all you collections saved within one transaction you must define that at the collection level


          Leo

          • 2. Re: Persistence problems
            andreea

            Hi Leo,


            Thanks for your prompt response.



            Leo van den Berg wrote on Jun 08, 2010 14:42:


            The thing I am missing is the action which starts it all and kicks-off the conversation 


            You mean this?




            <?xml version="1.0" encoding="UTF-8"?>
            <page xmlns="http://jboss.com/products/seam/pages"
                  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                  xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.2.xsd"
                  no-conversation-view-id="/TestCaseList.xhtml"
                  login-required="true">
            
               <begin-conversation join="true" flush-mode="MANUAL"/>
            
               <action execute="#{testCaseHome.wire}"/>
            
               <param name="testCaseFrom"/>
               <param name="testCaseId" value="#{testCaseHome.testCaseId}"/>
            
            
               <navigation from-action="#{testCaseHome.persist}">
                  <rule if-outcome="persisted">
                     <end-conversation/>
                     <redirect view-id="/TestCaseList.xhtml"/>
                  </rule>
               </navigation>
            
               <navigation from-action="#{testCaseHome.update}">
                  <rule if-outcome="updated">
                     <end-conversation/>
                     <redirect view-id="/TestCaseList.xhtml"/>
                  </rule>
               </navigation>
            
               <navigation from-action="#{testCaseHome.remove}">
                  <rule if-outcome="removed">
                     <end-conversation/>
                     <redirect view-id="/TestCaseList.xhtml"/>
                  </rule>
               </navigation>
            
            </page>
            





            Something else you should add is cascading to you entity-classes. If you want to have all you collections saved within one transaction you must define that at the collection level


            Will do.


            And yes, I am using the Seam-generated EntityHome.


            Greets,
            Andreea