7 Replies Latest reply on Jul 15, 2010 1:47 AM by shane lee

    One to many persisting issue

    shane lee Newbie

      Having an issue with adding a list of attachments. My relationship is a bi-directional one to many relationship, inquiry has one or many attachments.


      Code snippet for inquiry:



      @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "inquiry")
          public Set<Attachment> getAttachments() {
              return attachments;
          }



      Code snippet for attachment:



      @ManyToOne(fetch = FetchType.LAZY)
          @JoinColumn(name = "inquiry_id",nullable=false)
          @NotNull
          public Inquiry getInquiry() {
              return inquiry;
          }



      i have a screen where i can upload as many attachments as i want. When im finished uploading attachments i call save.  But every time i add an attachment to inquiry entity which is managed, im just updating the same attachment instance in the inquiry.


      Can anyone see what is wrong with the way im utilising entity manager and persisting?


      Code snippet for inquiry action class:



      @In
          @Out
          private inquiry.model.Inquiry newInquiry;
          
          @In(required=false,create=true)
          Attachment newAttachment;
      
       public void addAttachment(){
              newAttachment.setInquiry(entityManager.find(inquiry.model.Inquiry.class, newInquiry.getId()));
              newInquiry.getAttachments().add(newAttachment);
          }
          
          @End
          public void save(){
              entityManager.persist(newInquiry);
              this.sendEmail();
              facesMessages.add("Successfully submitted web inquiry form");
          }





      Thanks,
      Shane.






        • 1. Re: One to many persisting issue
          Thomas Jonsson Newbie

          Do you create a new Attachment object after you add newAttachment?

          • 2. Re: One to many persisting issue
            shane lee Newbie

            Thanks for your reply thomas.


            The goal of this exercise is to have a form inquiry wizard. On page one i add inquiry details. On page two then i upload as many attachments as i like. This means returning to same attachment page multiple times.  When i have finished uploading, only then do i save and persist the inquiries attachments to the database. 


            After more testing i have discovered what is happening. Im using a stateful session bean and CMT. That means that every time i upload an attachment, that is every page request to attachment.xhtml, hibernate is automatically flushing new inquiry and its attachment to database, due to end of transaction.  This means the first time i upload an attachment an insert occurs. The second time i upload an attachment it updates the existing attachment in the database. This means injecting the newAttachment is not instantiting a new object every time.




            So to go from here i have a few questions.
            How do i instantiate a new attachment object every time i upload? Do i have to change the scope type of the injected newAttachment to event, as in per page request?



            @In(required=false,scope=ScopeType.EVENT)
                Attachment newAttachment;



            When beginning the conversation, to prevent automatic flushing, as i only want to persist attachment(s) when i hit save on attachments page, do i set


            flushMode = FlushModeType.MANUAL

            ?


            Thanks,
            Shane.


            • 3. Re: One to many persisting issue
              shane lee Newbie

              In relation to my first question, how do i instantiate a new attachment object every time i upload(multiple page request).


              If i set scope type in Injection as:



              @In(required=false,scope=ScopeType.EVENT)
                  Attachment newAttachment;



              that gives me a null value.


              if i instantaite a new attachment object when i invoke addAttachment that gives me a null value too.



              Comment out @In and inside addAttachment() i instantiate attachment
              public void addAttachment(){
              newAttachment = new Attachment();
              newInquiry.getAttachments().add(newAttachment);



              The only way i can get it to work is if i inject in newAttachment and instantiate a new attachment object in addAttachment and clone the values:



              @In(required=false)
                  Attachment newAttachment;
              
               public void addAttachment(){
              
                    Attachment attachment = new Attachment();
                     attachment.setDescription(newAttachment.getDescription());
                      attachment.setDoc(newAttachment.getDoc());
                      attachment.setFileContentType(newAttachment.getFileContentType());
                      attachment.setFileSize(newAttachment.getFileSize());
                      attachment.setInquiry(newInquiry);*/
                      newInquiry.getAttachments().add(attachment);
                      //entityManager.persist(newAttachment);
                  }



              This seems very long winded? How can i apply request values to a newly created newAttachment object every time i request the same page?






              • 4. Re: One to many persisting issue
                shane lee Newbie

                In relation to second question i have that working now. i set the attribute flush mode to manual when i begin the conversation.



                @Begin(flushMode = FlushModeType.MANUAL) 




                It says in seam reference documentation:




                By default, the persistence context is flushed (synchronized with the database) at the end of each transaction.
                    This is sometimes the desired behavior. But very often, we would prefer that all changes are held in memory and
                    only written to the database when the conversation ends successfully. This allows for truly atomic conversations.

                So now when i add my attachment, i add to newinquiry each time, as newInquiry is a managed object. When i hit save i call flush which synchrnoizes all my changes to the database.




                public void addAttachment(){
                        Attachment attachment = new Attachment();
                        attachment.setDescription(newAttachment.getDescription());
                        attachment.setDoc(newAttachment.getDoc());
                        attachment.setFileContentType(newAttachment.getFileContentType());
                        attachment.setFileSize(newAttachment.getFileSize());
                        attachment.setFileName(newAttachment.getFileName());
                        attachment.setInquiry(newInquiry);
                        newInquiry.getAttachments().add(attachment);
                        facesMessages.add("Added attachment to inquiry form filename: {0}",newAttachment.getFileName());
                    }
                    
                    @End
                    public void save(){
                        entityManager.flush();
                        this.sendEmail();
                        facesMessages.add("Successfully submitted web inquiry form");
                    }







                • 5. Re: One to many persisting issue
                  Thomas Jonsson Newbie

                  Great that you solved flush mode issue. In most cases I go for the manual flush mode, but of course, that depends on the situation.


                  I don't work that much with injecting pojos in action classes. So this below code assumes that you in the view page access the attachment by nameOfActionComponent.newAttachment. Otherwise elaborate with the @Out annotation.




                  public void addAttachment(){
                          newInquiry.getAttachments().add(newAttachment);
                          newAttachment = new Attachment();
                          facesMessages.add("Added attachment to inquiry form filename: {0}",newAttachment.getFileName());
                      }
                  
                  public Attachment getNewAttachment() {
                  return new Attachment();
                  }
                  
                  public void setNewAttachment(Attachment newAttachment) {
                  this.newAttachment = newAttachment;
                  }



                  • 6. Re: One to many persisting issue
                    Thomas Jonsson Newbie

                    I typed wrong in my last post.



                    public void addAttachment(){
                            newInquiry.getAttachments().add(newAttachment);
                            newAttachment = new Attachment();
                            facesMessages.add("Added attachment to inquiry form filename: {0}",newAttachment.getFileName());
                        }
                    
                    public Attachment getNewAttachment() {
                    return newAttachment;
                    }
                    
                    public void setNewAttachment(Attachment newAttachment) {
                    this.newAttachment = newAttachment;
                    }



                    • 7. Re: One to many persisting issue
                      shane lee Newbie

                      Hi Thomas, i made those changes but still did not work. So i reverted back to cloning values from newAttachment context variable into a newly instantiated Attachment object every time.


                      My injection is as follows:



                      @In(required=false,create=true)
                          Attachment newAttachment; 



                      I just thought that every time i addAttachment this context variable would be instantiated and apply request values.


                      Thanks,
                      Shane.