1 2 Previous Next 25 Replies Latest reply on Jul 25, 2006 8:26 AM by denis-karpov

    Hibernate Validation / Page Scope --> allways new entity

    mrwhite

      Hi everybody,
      i got a strange data manipulation problem.

      I have a simple form i use for editing and inserting:

      <h:form>
       <s:validateAll>
       <div>
       <h:outputLabel for="firstname">Vorname: </h:outputLabel>
       </div>
       <div>
       <h:inputText id="firstname" value="#{newClientPerson.firstname}" size="70" maxlength="70" required="true"/>
       <span class="errors"><h:message for="firstname"/></span>
       </div>
       <div>
       <h:outputLabel for="lastname">Nachname: </h:outputLabel>
       </div>
       <div>
       <h:inputText id="lastname" value="#{newClientPerson.lastname}" size="70" maxlength="70" required="true"/>
       <span class="errors"><h:message for="lastname"/></span>
       </div>
       <div>
       <h:commandButton value="Speichern" action="#{clientPersonAction.saveClientPerson}"/>
       </div>
       </s:validateAll>
       </h:form>
      



      And i have the following Action:
      @Stateless
      @Name("clientPersonAction")
      public class ClientPersonEditAction implements ClientPersonEdit{
      
       @PersistenceContext
       private EntityManager em;
      
       @RequestParameter()
       private Long clientPersonId;
      
       @In(required=false)
       @Out(scope=ScopeType.PAGE,required=false)
       @Valid
       private ClientPerson newClientPerson;
      
       @Factory("newClientPerson")
       public void createNewClientPerson()
       {
       if(clientPersonId != null)
       {
       ClientPersonDAO clientPersonDAO = new ClientPersonDAO(em);
       newClientPerson = clientPersonDAO.getClientPersonById(clientPersonId);
       System.out.println("createNewClientPerson:" + newClientPerson.getId());
       }
       else
       {
       newClientPerson = new ClientPerson();
       }
       }
      
       public String saveClientPerson() {
       ClientPersonDAO clientPersonDAO = new ClientPersonDAO(em);
       System.out.println("newClientPerson.getId():" + newClientPerson.getId());
       clientPersonDAO.merge(newClientPerson);
       return "home";
       }
      
      
      }
      



      The Entity

      package org.jboss.seam.example.client;
      
      import java.io.Serializable;
      
      import javax.persistence.Entity;
      
      import org.hibernate.validator.NotNull;
      import org.jboss.seam.ScopeType;
      import org.jboss.seam.annotations.Scope;
      
      @Scope(ScopeType.EVENT)
      @Entity
      public class ClientPerson extends Client implements Serializable{
      
       private static final long serialVersionUID = -7846741936105611777L;
       private String firstname;
       private String lastname;
      
       @NotNull
       public String getFirstname() {
       return firstname;
       }
      
       public void setFirstname(String firstname) {
       this.firstname = firstname;
       }
      
       @NotNull
       public String getLastname() {
       return lastname;
       }
      
       public void setLastname(String lastname) {
       this.lastname = lastname;
       }
      
      
      
      
      
      }
      



      When I fill out the form and save a new object its correctly saved in the database. When some id is passed to the action i can edit the values from the database object and save everything back.

      BUT: When i open a persisted object from the database and remove the field content from a field that has for example the hibernate validator annotation @NotNull i get the normal message "value required". Then i type in correct data and press the save button a new entity is persisted with all the other fields from the "old" entity but under a different id.

      Summary: Adding and editing works. Saving a persisted object after a hibernate validation error creates a new one in the database.

      Any suggestions on that?





        • 1. Re: Hibernate Validation / Page Scope --> allways new entity
          gavin.king

          So this is something I hate about JSF validation. A JSF validator cannot be used to test nullability.

          You need to say <h:inputText required="true" .... />

          Sucks, huh?

          • 2. Re: Hibernate Validation / Page Scope --> allways new entity
            mrwhite

            Hi Gavin, you can checkout the facelet page i posted. i already use the required="true" attribute.

            And the problem is not the check for nullability. The problem is that a new database entity is created and the exisiting one is not updated when a validaton fault appears.


            • 3. Re: Hibernate Validation / Page Scope --> allways new entity
              bfo81

              I might be wrong, but I think the problem is that you use a STATELESS bean. And this one forgets its state after invokation of a method. I.e. it forgets your ClientPerson Entity and the id as well. So after every reload of the form a new ClientPerson is generated - without an id - and so the EntityManager always creates a new one.

              I must confess I still didn't get 100% familiar with states and scopes and stuff either, though working with Seam for a few weeks now. You need to make some mistakes when using Seam in order to exactly understand what things are good for. Trial and error, learning by doing... that's the hard work you must do before being rewarded with the great possibilties Seam offers ;).

              • 4. Re: Hibernate Validation / Page Scope --> allways new entity
                mrwhite

                Hi bfo81m,
                thanks for your tipps i am running through the same scope confusing. ;-)

                i also tried to make my clientPersonAction component stateful, but the behavior is the same.


                • 5. Re: Hibernate Validation / Page Scope --> allways new entity
                  pmuir

                  You would need to make it conversational to avoid the behaviour bfo81 is talking about (if that is the root of your problem). You log the id of the object before merging it. Is it always correct set correctly? What is the code for your DAO? Is it a simple em.merge()?

                  • 6. Re: Hibernate Validation / Page Scope --> allways new entity
                    mrwhite

                    Hi petemuir,

                    make it conversational

                    what exactly? my "clientPersonAction" component or the newClientPerson member.

                    the whole form is limited to this one page. why should it be conversational?
                    I thougt a conversation is something like a sub-session for a whole bunch of pages and their states. correct me, if i am wrong.

                    you log the id of the object before merging it. Is it always correct set correctly?

                    no, the id gets lost, after the described use case.

                    What is the code for your DAO? Is it a simple em.merge()?

                    you´re right. just a merge.

                    • 7. Re: Hibernate Validation / Page Scope --> allways new entity
                      bfo81

                      It's always useful to give an Editor Bean the Conversation Scope.

                      The method that's invoked by the preceding page (e.g. list page) should be annotated with @begin(nested=true) and the method being called before leaving the editor page (e.g. save) should be annotated with @end.

                      If you do so, the editor bean keeps its state (especially the edited entity bean) exactly as long as the user is on the editor page. And I believe that's exactly what you want :).


                      (I made this one bold 'cause it's on of my conclusions of the last weeks working with Seam. if I would have known it before I wouldn't have lost half of my hair ;)).




                      • 8. Re: Hibernate Validation / Page Scope --> allways new entity
                        mrwhite

                        First thanks for the answer.

                        But why do i need a conversation for that. it works fine when no validation fault appears.

                        And where should i put the @Begin annotation?

                        I just have my clientPersonService to deliver a simple list:

                        @Stateless
                        @Name("clientPersonService")
                        public class ClientPersonServiceImpl implements ClientPersonService {
                        
                         @PersistenceContext
                         private EntityManager em;
                        
                         public List <ClientPerson> getAllClientPerson()
                         {
                         ClientPersonDAO clientPersonDAO = new ClientPersonDAO(em);
                         return clientPersonDAO.getAllClientPerson();
                         }
                        }


                        And a simple link to the edit page:
                        <f:param name="clientPersonId" value="#{clientPerson.id}"/>




                        • 9. Re: Hibernate Validation / Page Scope --> allways new entity
                          bfo81

                           

                          "mrwhite" wrote:
                          But why do i need a conversation for that. it works fine when no validation fault appears.
                          That's the point. If there's no validation fault, everything is ok. BUT: If there is one, then the page needs to be reloaded. Hence the state of the editor page must be "reloaded", too. And a good way to do this is to keep the state in a Conversation.

                          And where should i put the @Begin annotation?
                          Which method do you call before the edit page is displayed?

                          To make sure we're talking about the same: I usually have a list page with a list bean, and an edit page with an edit bean. And the edit bean contains the following methods:

                          @Begin(nested=true)
                          public String create() {...} //To create a new entry

                          @Begin(nested=true)
                          public String edit() {...} //To edit an existing entry

                          @End
                          public String cancel() {...} //If the cancel button on the edit page is pressed

                          @End
                          public String save() {...} //If the save button is pressed (and validation was successfull)

                          @End
                          public String delete() {...} //If the delete button is pressed

                          That's the "classic" pattern. Maybe you do it another way, so I wanted to make clear what I'm talking about ;).

                          • 10. Re: Hibernate Validation / Page Scope --> allways new entity
                            mrwhite

                            Ok, i will try this.

                            But: when i have a link in a template and a user doesnt press the save button is the conversation still open?

                            • 11. Re: Hibernate Validation / Page Scope --> allways new entity
                              bfo81

                              Unfortunatley yes. But I think it's not likely that this will cause any problems. If the user opens another editor page later then it will get its own new conversation. The old conversation will remain in memory and get deleted after a certain amount of time.

                              And there's even another problem you brought into my mind: After clicking save the user gets redirected to the list page. If he presses the back button of his browser he gets back to the edit page... with no active conversation. But this can be avoided by adding the follwing annotation to the edit bean: @Conversational(ifNotBegunOutcome="...backToTheList...")
                              This redirects the user to the list page ;).

                              • 12. Re: Hibernate Validation / Page Scope --> allways new entity
                                mrwhite

                                hi bfo,
                                I tried your approach but now i get no changes to my entity.

                                Steps:
                                1. I added a new entry
                                2. i click on the link and get on the edit page
                                3. i remove a property text that has a hibernate validator
                                4. i get the validator message
                                5. i fill in a new value
                                6. i click on the save button and come back to my list
                                7. the entity is the same without any changes.

                                ???

                                • 13. Re: Hibernate Validation / Page Scope --> allways new entity
                                  bfo81

                                  First: Forget what I just said about @Conversational. When clicking the back button the browser loads the page from its cache.

                                  Ok, now back to your prob. Maybe your list isn't up to date. Try it like this:

                                  EditBean:

                                  public String save() {
                                   ...
                                   Events.instance().raiseEvent("whateverListChanged");
                                   return "saved";
                                  );


                                  ListBean:
                                  @Observer("whateverListChanged")
                                  public void theMethodThatLoadsTheListFromTheDb(..) {...}


                                  If this isn't the source of the problem just post your code and I'll have a look over it ;).

                                  • 14. Re: Hibernate Validation / Page Scope --> allways new entity
                                    mrwhite

                                    The list component is a stateless session bean.

                                    @Stateless
                                    @Name("clientPersonService")
                                    public class ClientPersonServiceImpl implements ClientPersonService {
                                    
                                     @PersistenceContext
                                     private EntityManager em;
                                    
                                     public List <ClientPerson> getAllClientPerson()
                                     {
                                     ClientPersonDAO clientPersonDAO = new ClientPersonDAO(em);
                                     return clientPersonDAO.getAllClientPerson();
                                     }
                                    }



                                    so there is nothing cached or saved.
                                    the list must be up to date because the new created entities of my "root problem" appear after the update of the "original" entity. and i checked the list against the database. everything is in sync.

                                    1 2 Previous Next