1 2 Previous Next 17 Replies Latest reply on Oct 5, 2007 9:00 PM by dhinojosa

    Need help updating multi-table dataTable - injecting list?

    asookazian

      I have successfully created a dataTable based on two different DB tables with a 1:1 relationship. I need to know for CRUD purposes, how will it be possible to update the DB in a JSF/Seam/EJB3 framework this app is currently in.

      Specifically, as in the pic below, you see that the user can change multiple columns in multiple rows for one of the entities (in this case only the CreditCard data can be updated, the Customer data is read-only).

      I've seen in the hotel booking example that you inject the instance of the entity bean that had its setter methods called when the form was submitted in the JSF. In this case, it's not just one row that's being set and updated, it's potentially multiple rows in one transaction/use-case.

      Does Seam support this? If so, how can I persist multiple rows/entity instances in a single transaction? It seems that I must inject the entire List of modified rows/entities into the SFSB first.

      See partial code below:

      CustomerAction.java (SFSB):

      @DataModel
       private List<Customers> customers;
      
       @DataModelSelection
       private Customers customer;
      
       @Factory("customers")
       public void find()
       {
      
       customers = em.createQuery("select c, cc "+
       "from Customers c inner join c.creditCard as cc "+
       "where c.userId = :userId")
       .setParameter("userId", user.getUserId())
       .getResultList();
      
       }


      myJSF.xhtml:

      <h:form>
      
       <h:dataTable value="#{customers}" var="customer"
       bgcolor="#F1F1F1" border="10" width="100%" cellpadding="0" cellspacing="0"
       dir="LTR" frame="hsides">
       <h:column>
       <f:facet name="header">First Name</f:facet>
      
       <h:outputText value="#{customer[0].firstName}"/>
       </h:column>
      
       <h:column>
       <f:facet name="header">Last Name</f:facet>
      
       <h:outputText value="#{customer[0].lastName}"/>
       </h:column>
      
       <h:column>
       <f:facet name="header">Street Name</f:facet>
       <h:outputText value="#{customer[0].streetName}"/>
       </h:column>
      
       <h:column>
       <f:facet name="header">CC #</f:facet>
      
       <h:inputText value="#{customer[1].creditcardnumber}"/>
       </h:column>
      
       <h:column>
       <f:facet name="header">Company Name</f:facet>
      
       <h:inputText value="#{customer[1].companyname}"/>
       </h:column>
      
      
       </h:dataTable>
      
       <h:commandButton value="submit" action="#{customerAction.submit}"/>
       </h:form>


      [img]http://i145.photobucket.com/albums/r234/rabiesjoy/java/multi-table-dataTable.jpg[/img]

        • 2. Re: Need help updating multi-table dataTable - injecting lis
          dhinojosa

          Are you in for a treat....

          I don't know if you know this.... If your bean is stateful, your queries do not need a join, all relevant information will be retreived.

          • 3. Re: Need help updating multi-table dataTable - injecting lis
            dhinojosa

            So, in answer to your real question...I have to ask, do you have duplicate tables of customer and credit card in one database or separate databases?

            • 4. Re: Need help updating multi-table dataTable - injecting lis
              asookazian

              What do you mean by "duplicate tables"? There is one Customer table and one CreditCard table in one RDBMS (sql server in this case).

              I don't understand your "treat" part... Are you saying if my session bean is stateful, I don't need to join them?

              How do I get all the updates CreditCard rows/entities injected into the SFSB for perstistence processing???

              • 5. Re: Need help updating multi-table dataTable - injecting lis
                asookazian

                I meant to say updated (modified) CreditCard rows/entities...

                this damn forum doesn't allow us to edit our posts?!?!?!?

                • 6. Re: Need help updating multi-table dataTable - injecting lis
                  asookazian

                  OK. so I ran the use case again. modified three input fields. clicked the submit button on the JSF.

                  In the debugger, I have a stop at the first line of the SFSB's submit() method (which is called by submit click in JSF).

                  The values in the variables tab were appropriately changed to reflect what I had typed in the JSF form.

                  So I guess I don't have to explicitly inject them with an @In annotation. How is it available, by the way? Via the following code?:

                  @DataModel
                   private List<Customers> customers;
                  


                  Now when it exec's the em.persist(customers) call in the submit() method, I get the following exception:

                  Caused by: java.lang.IllegalArgumentException: Unknown entity: java.util.ArrayList
                  


                  So that means I can't do the update in one em.persist() call? I need to pull out the two entities from the customers List and go from there I guess...

                  • 7. Re: Need help updating multi-table dataTable - injecting lis
                    asookazian

                    Well I guess the customers instance variable is still available b/c the SFSB didn't go out of scope (conversation didn't end yet?) Since it's an instance variable, it's still able to be referenced by the same class...

                    • 8. Re: Need help updating multi-table dataTable - injecting lis
                      dhinojosa

                      You update not with the persist method but with the merge method:

                      So you can do

                      @Name("customerAction")
                      @Scope(<PUT SCOPE HERE>)
                      @Stateful
                      public class CustomerAction {
                      
                      
                       @PersistenceContext(....);
                       private EntityManager em;
                      
                       @DataModel
                       private List<Customers> customers;
                      
                       @DataModelSelection
                       private Customers customer;
                      
                       @Factory("customers")
                       public void find()
                       {
                      
                       customers = em.createQuery("select c"+
                       "from Customers c " +
                       "where c.userId = :userId")
                       .setParameter("userId", user.getUserId())
                       .getResultList();
                      
                       }
                      
                       public void update() {
                      
                       em.merge(customer)
                       }
                      }
                      
                      
                      




                      • 9. Re: Need help updating multi-table dataTable - injecting lis
                        dhinojosa

                        also I changed the query on the code snippet. What that means is you can change your page to:

                        <h:form>
                        
                         <h:dataTable value="#{customers}" var="customer"
                         bgcolor="#F1F1F1" border="10" width="100%" cellpadding="0" cellspacing="0"
                         dir="LTR" frame="hsides">
                         <h:column>
                         <f:facet name="header">First Name</f:facet>
                        
                         <h:outputText value="#{customer.firstName}"/>
                         </h:column>
                        
                         <h:column>
                         <f:facet name="header">Last Name</f:facet>
                        
                         <h:outputText value="#{customer.lastName}"/>
                         </h:column>
                        
                         <h:column>
                         <f:facet name="header">Street Name</f:facet>
                         <h:outputText value="#{customer.streetName}"/>
                         </h:column>
                        
                         <h:column>
                         <f:facet name="header">CC #</f:facet>
                        
                         <h:inputText value="#{customer.creditCard.creditcardnumber}"/>
                         </h:column>
                        
                         <h:column>
                         <f:facet name="header">Company Name</f:facet>
                        
                         <h:inputText value="#{customer.creditCard.companyname}"/>
                         </h:column>
                        
                        
                         </h:dataTable>
                        
                         <h:commandButton value="submit" action="#{customerAction.update}"/>
                         </h:form>
                        
                        
                        


                        • 10. Re: Need help updating multi-table dataTable - injecting lis
                          asookazian

                          ok thx for your reponses.

                          your way is an alternative to my way, with your EJBQL being simpler.

                          when the user clicks the submit button, will your way update only one customer entity (one row)? or all the rows that they have modified?

                          will I need to do multiple merge calls to do multiple updates?

                          • 11. Re: Need help updating multi-table dataTable - injecting lis
                            asookazian

                            ok, cool. The updates worked for 3 different rows (6 cells total modified in JSF). I verified with t-sql select to check updates were successfull.

                            only thing is I am seeing the following error(s) after submit:

                            14:19:23,918 INFO [CustomerAction] in getCustomers(): user.getUserId() = 4461
                            14:19:24,918 INFO [CustomerAction] in destroy()
                            14:19:38,573 INFO [CustomerAction] in getCustomers(): user.getUserId() = 4461
                            14:19:38,620 INFO [CustomerAction] in submit()
                            14:19:50,588 INFO [CustomerAction] in submit()
                            14:20:13,056 ERROR [SeamPhaseListener] uncaught exception
                            java.lang.NullPointerException
                             at org.jboss.seam.jsf.AbstractSeamPhaseListener.afterPhase(AbstractSeamPhaseListener.java:157)


                            I will try to determine if your way of doing is better or not. this is the submit() code:

                            Iterator it = myList.iterator();
                            
                             while (it.hasNext()) {
                             Object[] result = (Object[])it.next();
                             Customers customers = (Customers)result[0];
                             em.merge(customers);
                             CreditCard creditCard = (CreditCard)result[1];
                             em.merge(creditCard);
                             }


                            Is it possible to do it all in one transaction?? Isn't the above doing two merges(updates) per row??

                            • 12. Re: Need help updating multi-table dataTable - injecting lis
                              dhinojosa

                              Oops....I see your point now.

                              The answer is one....
                              If you wanted to do all the rows, you can change the update method to:

                               public void update() {
                               for(Customer customer: customer) {
                               em.merge(customer)
                               }
                               }
                              
                              


                              Therefore you wouldn't need
                               @DataModelSelection
                               private Customers customer;
                              


                              Since nothing is being selected.

                              • 13. Re: Need help updating multi-table dataTable - injecting lis
                                dhinojosa

                                Just put a transaction annotation above your submit/update method

                                @TransactionAttribute(TransactionAttributeType.<YOUR_TYPE>)
                                public void update() {
                                .........
                                }

                                • 14. Re: Need help updating multi-table dataTable - injecting lis
                                  dhinojosa

                                  Ooops correction:

                                  public void update() {
                                   for(Customer customer: customer) {
                                   em.merge(customer)
                                   }
                                   }
                                  
                                  


                                  1 2 Previous Next