6 Replies Latest reply on Sep 22, 2009 4:46 PM by Ercan Isık

    CRUD update problem

    Ercan  Isık Newbie

      Hi ..I have an little problem .In my Example I want to edit my user detail .but every time when push Update button it creates new data like new user..but I want to update existing user. :( I think problem on updatePerson() action ..


      here is my codes


      This is person class



      import java.util.HashSet;
      import java.util.Set;
      
      import javax.persistence.CascadeType;
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.FetchType;
      import javax.persistence.GeneratedValue;
      import javax.persistence.Id;
      import javax.persistence.OneToMany;
      import javax.persistence.Table;
      
      import org.jboss.seam.annotations.Name;
      
      @Entity
      @Table(name = "PERSON")
      public class Person {
      
           private Long id;
           public String firstname;
           public String lastname;
           public String phonenumber;
           public String addres;
      
           private Set<PersonLesson> personLessons = new HashSet<PersonLesson>(0);
      
      
           @Id
           @GeneratedValue
           @Column(name = "PERSON_ID")
         
           public Long getId() {
                return id;
           }
      
           public void setId(Long id) {
                this.id = id;
           }
      
           @Column(name = "FIRST_NAME")
           public String getFirstname() {
                return firstname;
           }
      
      
           public void setFirstname(String firstname) {
                this.firstname = firstname;
           }
      
           @Column(name = "LAST_NAME")
           public String getLastname() {
                return lastname;
           }
      
           public void setLastname(String lastname) {
                this.lastname = lastname;
           }
      
           @Column(name = "PHONE_NUMBER")
           public String getPhonenumber() {
                return phonenumber;
           }
      
           public void setPhonenumber(String phonenumber) {
                this.phonenumber = phonenumber;
           }
      
           @Column(name = "ADDRES")
           public String getAddres() {
                return addres;
           }
      
           public void setAddres(String addres) {
                this.addres = addres;
           }
           @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "person")
           public Set<PersonLesson> getPersonLessons() {
                return personLessons;
           }
      
           public void setPersonLessons(Set<PersonLesson> personLessons) {
                this.personLessons = personLessons;
           }
      
      }
      



      This is PersonUtil class



      import java.util.ArrayList;
      import java.util.List;
      
      import javax.persistence.EntityManager;
      
      import org.jboss.seam.Component;
      import org.jboss.seam.ScopeType;
      import org.jboss.seam.annotations.Name;
      import org.jboss.seam.annotations.Scope;
      
      @Name("personutil")
      @Scope(ScopeType.CONVERSATION)
      public class PersonUtil   {
      
           private Person activePerson ;
           private List<Person> persons = new ArrayList<Person>();
           
        private Lesson newLesson ;
      
      
           public PersonUtil() {     
           activePerson = new Person();
           
                initPersonList();
           }
      
      
      
      
      
           public void activePerson(Person kisi){
                
                this.activePerson = kisi ;
                
                
           }
      
           public Lesson getNewLesson() {
                return newLesson;
           }
      
      
      
           public void setNewLesson(Lesson newLesson) {
                this.newLesson = newLesson;
           }
      
      
      
      
      
      
           public Person getActivePerson() {
                return activePerson;
           }
      
      
      
           public void setActivePerson(Person activePerson) {
                this.activePerson = activePerson;
           }
      
      
      
           public void initPersonList() {
                EntityManager em = (EntityManager) Component.getInstance("entityManager");
                List<Person>  result = em.createQuery("from Person")
                          .getResultList();
      
                setPersons(result);
           }
      
           public List<Person> getPersons() {
                return persons;
           }
      
           public void setPersons(List<Person> persons) {
                this.persons = persons;
           }
      
           public void initPerson(Person person) {
                this.activePerson = person;
                
           }
           public void savePerson() {
                EntityManager em = (EntityManager) Component.getInstance("entityManager");
                em.persist(activePerson);
                
                em.flush();
           
           }
           
           public void removePerson(Person person) {
                EntityManager em = (EntityManager) Component.getInstance("entityManager");
           
                     
                em.remove(person);
                em.flush();
           }
           public void updatePerson(Person person) {
                EntityManager em = (EntityManager) Component.getInstance("entityManager");
                em.persist(person);
                em.flush();
           }
      }
      



      This is existing user XHTML



      <ui:composition xmlns="http://www.w3.org/1999/xhtml"
           xmlns:ui="http://java.sun.com/jsf/facelets"
           xmlns:h="http://java.sun.com/jsf/html"
           xmlns:f="http://java.sun.com/jsf/core"
           xmlns:a4j="http://richfaces.org/a4j"
           xmlns:rich="http://richfaces.org/rich">
      
      
           <h:form>
      
                <rich:dataTable onRowMouseOver="this.style.backgroundColor='#F8F8F8'"
                     onRowMouseOut="this.style.backgroundColor='#{a4jSkin.tableBackgroundColor}'"
                     width="400" var="kisi" value="#{personutil.persons}">
                     <f:facet name="header">
                          <rich:columnGroup>
      
                               <rich:column rowspan="1">
                          
                                         <h:outputText value="KISILER" />
                               
      
      
      
      
                               </rich:column>
                               <rich:column colspan="4">
                                    <h:outputText value="DUZEN" />
      
                               </rich:column>
      
      
                          
      
                          </rich:columnGroup>
      
                     </f:facet>
      
                     <rich:column rowspan="1">
                          <h:outputText value="#{kisi.firstname}#{kisi.lastname}" />
                     </rich:column>
      
      
                     <rich:column>
                          <a4j:commandButton action="#{personutil.removePerson(kisi)}"
                               value="Sil" />
                     </rich:column>
      
                     <rich:column>
                          <a4j:commandButton action="#{personutil.activePerson(kisi)}"
                               value="Edit" />
                     </rich:column>
      
                     <rich:column>
                          <a4j:commandButton action="#{personlessonutil.activePerson(kisi)}"
                               value="Dersleri" />
                     </rich:column>
                     
                </rich:dataTable>
      
           </h:form>
      
      
      
      
      </ui:composition>



      And the last for update page..After pressing edit button it goes this page



      
      
      <ui:composition xmlns="http://www.w3.org/1999/xhtml"
            xmlns:ui="http://java.sun.com/jsf/facelets"
            xmlns:h="http://java.sun.com/jsf/html"
            xmlns:f="http://java.sun.com/jsf/core"
            xmlns:a4j="http://richfaces.org/a4j"
            xmlns:rich="http://richfaces.org/rich">
              <h:form>    
                     
                          <f:facet name="header">
                              <rich:columnGroup>
                                
                                  <rich:column colspan="4">
                                  <rich:spacer />
                                  </rich:column>
                                  <rich:column colspan="1">
                                      <h:outputText value="DUZEN" />
                                  </rich:column>
                                  <rich:column breakBefore="true">
                                      <h:outputText value="Ad" />
                                  </rich:column>
                                  <rich:column>
                                      <h:outputText value="Soyad" />
                                  </rich:column>
                                 
                                  <rich:column>
                                      <h:outputText value="Telefon" />
                                  </rich:column>
                                   <rich:column>
                                      <h:outputText value="Adress" />
                                  </rich:column>
                                   
                              </rich:columnGroup>
                          </f:facet>
                        
                          <rich:column>
                          <h:inputText value="#{personutil.activePerson.firstname}" /></rich:column>
                          
                          
                          
                              <rich:column>
                                  <h:inputText value="#{personutil.activePerson.lastname}"></h:inputText>
                    
                              </rich:column>
                              <rich:column>
                                  <h:inputText value="#{personutil.activePerson.phonenumber}"></h:inputText>
                                 
                              </rich:column>
                              
                              <rich:column>
                                  <h:inputText value="#{personutil.activePerson.addres}"></h:inputText>
                                 
                              </rich:column>
                          
          
                              <rich:column>
                                 <a4j:commandButton action="#{personutil.updatePerson()}" value="Update" />
                              </rich:column>
                    
      </h:form>
      </ui:composition>













        • 1. Re: CRUD update problem
          Arbi Sookazian Master

          Your problem may be here:


          public void updatePerson(Person person) {
                    EntityManager em = (EntityManager) Component.getInstance("entityManager");
                    em.persist(person);
                    em.flush();
               }



          em.persist(foo) is used to generate an insert statement via your persistence provider (typically Hibernate).


          You should use em.merge(foo) instead for updates.


          But also realize that the PersistenceContext acts as a 1st level cache during your conversations.  So that means if a user makes any changes to cells in a dataTable in a JSF form and submits, all you need to do is flush the PC via em.flush() if you're using Hibernate manual flush mode.  Otherwise, AUTO flush is the default so you don't need to code anything in your update method.


          Why are you not using @In EntityManager?  It would eliminate all the occurrences of this code:


          EntityManager em = (EntityManager) Component.getInstance("entityManager");



          From SiA book regarding the persistence manager (aka persistence context):


          ■ Manage entity instances within the scope of a single use case —Entities are managed
          via the persistence manager API. This API has methods to create, remove,
          update, find by id, and query entity instances. It also manages the life cycle of
          an entity instance as it moves between four possible states: transient, persisted,
          detached, and removed.
          ■ Maintain a persistence context —The persistence context is an in-memory cache of
          all entity instances that have been loaded into memory by this manager. It is the
          key to optimizing performance and enabling write-behind database operations
          (queued SQL statements). It’s often referred to as the “first-level” cache. The terms
          persistence context and persistence manager are often used interchangeably.
          ■ Perform automatic dirty checking —The state of managed objects that reside in the
          persistence context are monitored throughout the lifetime of the persistence
          context. When the persistence manager is flushed, the pending changes in the
          entity instances are sent to the database as a batch of SQL statements. Once an
          object becomes detached, changes to it are no longer monitored.

          • 2. Re: CRUD update problem
            Ercan  Isık Newbie

            Thx for reply. But I couldnt resolve  problem .  I used em.merge(person) but it creates again new data in my table .



            public void updatePerson(Person person) {
                      EntityManager em = (EntityManager) Component.getInstance("entityManager");
                      em.merge(person );
                      em.flush();
                 }



            and I have a action for ceating new person



            public void savePerson() {
                      EntityManager em = (EntityManager) Component.getInstance("entityManager");
                      em.persist(activePerson);
                      
                      em.flush();
                 
                 }



            They do the same job..I didnt understand .. And here my  Xhtml page for updating person



            
            
            <ui:composition xmlns="http://www.w3.org/1999/xhtml"
                  xmlns:ui="http://java.sun.com/jsf/facelets"
                  xmlns:h="http://java.sun.com/jsf/html"
                  xmlns:f="http://java.sun.com/jsf/core"
                  xmlns:a4j="http://richfaces.org/a4j"
                  xmlns:rich="http://richfaces.org/rich">
                    <h:form>    
                           
                                <f:facet name="header">
                                    <rich:columnGroup>
            
                                        <rich:column colspan="4">
                                        <rich:spacer />
                                        </rich:column>
                                        <rich:column colspan="1">
                                            <h:outputText value="DUZEN" />
                                        </rich:column>
                                        <rich:column breakBefore="true">
                                            <h:outputText value="Ad" />
                                        </rich:column>
                                        <rich:column>
                                            <h:outputText value="Soyad" />
                                        </rich:column>
                                       
                                        <rich:column>
                                            <h:outputText value="Telefon" />
                                        </rich:column>
                                         <rich:column>
                                            <h:outputText value="Adress" />
                                        </rich:column>
                                         
            
                                
                                </rich:columnGroup></f:facet>
                                <rich:column>
                                <h:inputText value="#{personutil.activePerson.firstname}" /></rich:column>
                                
                                
                                
                                    <rich:column>
                                        <h:inputText value="#{personutil.activePerson.lastname}"></h:inputText>
                          
                                    </rich:column>
                                    <rich:column>
                                        <h:inputText value="#{personutil.activePerson.phonenumber}"></h:inputText>
                                       
                                    </rich:column>
                                    
                                    <rich:column>
                                        <h:inputText value="#{personutil.activePerson.addres}"></h:inputText>
                                       
                                    </rich:column>
                                
                
                                    <rich:column>
                                       <a4j:commandButton action="#{personutil.updatePerson()}" value="Update" />
                                    </rich:column>
                        
                          
            </h:form>
            </ui:composition>



            I dınt usae dataTable  becouse of thıs I dont know what must I write  in personutil.updatePerson() in here ..it must be like personutil.updatePerson(person)? then it says  atemp to cerate or delete  whit null entitiy .... do I must  use Data Table ?

            • 3. Re: CRUD update problem
              Ercan  Isık Newbie

              ANd???? problem is continiuoss :((( any idea?

              • 4. Re: CRUD update problem
                Arbi Sookazian Master

                You need to understand that the merge() operation may result in an insert or update and why that happens.  It has to do with whether the entity is in attached - or managed - state or detached state.  If it's managed by EntityManager in the persistence context, then a merge() operation will result in an update if setter methods on that entity have been invoked.  If it's in detached state, then a merge() operation will result in an insert.


                See 3.7. Automatic state detection here: http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/objectstate.html


                e.g.


                // In the first entity manager
                Cat cat = firstEntityManager.find(Cat.class, catID);
                
                // In a higher layer of the application, detached
                Cat mate = new Cat();
                cat.setMate(mate);
                
                // Later, in a new entity manager
                secondEntityManager.merge(cat);   // update existing state
                secondEntityManager.merge(mate);  // save the new instance



                From SiA:


                Merging is a crude operation and should be avoided if possible. It first loads an entity
                instance with the same identifier as the detached instance into the current persistence
                context, resulting in a database read. Then, the property values from the detached
                instance are copied onto the properties of the managed instance. The main problem
                with this operation is that merging clobbers any changes that may have been made to
                the database record since the detached instance was retrieved (unless object versioning
                is used). There are other problems as well. If an entity instance with the same
                identifier as the detached instance has already been loaded into the current persistence
                context, a non-unique object exception is thrown because the uniqueness contract
                of entities in a persistence context is violated. You may also run into a lazy
                loading exception if you hit an uninitialized association on the detached instance during
                the merge. Avoid merging if at all possible.
                By using an extending persistence context, entity instances don’t become
                detached. Therefore, the persistence manager continues to track changes that are
                made to the entity. When it comes time to synchronize the entity with the database,
                calling the flush() method will do the trick within the scope of any transaction.



                So now that you understand the merge() operation, don't use it.  If you are using SMPC with Hibernate manual flush (which you typically should be if Hibernate is your persistence provider for JPA), then the entities that are initially attached when they are loaded via a JPAQL or Criteria query, etc. will not become detached until the conversation ends.


                Don't do this:


                @End
                public void submit(){
                    List<Foo> fooList = em.createQuery("from Foo").getResultList();
                    if (fooList.size() > 0) 
                       Foo foo = (Foo)fooList.get(0);
                    foo.setName("bar");
                    em.merge(foo);
                    em.flush();
                }



                Do this:


                @End
                public void submit(Foo foo){
                    List<Foo> fooList = em.createQuery("from Foo").getResultList();
                    if (fooList.size() > 0) 
                       Foo foo = (Foo)fooList.get(0);
                    foo.setName("bar");    
                    em.flush();
                }



                The 1st level cache (or persistence context or Hibernate Session) maintains dirty state checking for each entity that is managed by the EntityManager in the persistence context, so the state is automatically synchronized with the db (i.e. an update statement is issued by Hibernate) when you flush the persistence context and the tx is committed at the end of the method.


                • 5. Re: CRUD update problem
                  Ercan  Isık Newbie

                  It does not work :(((..or i am missunderstood some thing or missing..can u pleace in my code?in updetePerson function?

                  • 6. Re: CRUD update problem
                    Ercan  Isık Newbie

                    Hi...I understand that my problem is  I cant find data in data base which I inserted before..   I used this



                    public void updatePerson(Person person){
                              EntityManager em = (EntityManager) Component.getInstance("entityManager");
                              person = em.find(Person.class, activePerson);
                                
                              em.merge(person);
                              em.flush();
                           
                           
                            
                              
                          }



                    But it gives

                    "#{personutil.updatePerson(personutil.activePerson(kisi))}: java.lang.IllegalArgumentException: id to load is required for loading" 

                    this error.How can I fix it?


                    activePerson is the object that I have used in



                    public void savePerson() {
                              EntityManager em = (EntityManager) Component.getInstance("entityManager");
                    
                              em.persist(activePerson);
                              
                              em.flush();
                         
                         }


                    here...