7 Replies Latest reply on May 3, 2009 5:34 PM by maciekpazur

    Collection refreshing?

    maciekpazur

      I'm fighting a very strange problem while trying to implement simple message system for my application.


      I use Hibernate for persistence and have three entities - User, MessageFolder and Message. User has two elements of type MessageFolder: inbox and sentMessages. MessageFolder contains a list of Messages.


      I have a bean MessagesUI, which main method is:


      public void sendMessage() {
           message.setFrom(loggedUser);
              message.getTo().receiveMessage(receivedMessage);
              entityManager.merge(receivedMessage.getTo());
           message.getFrom().sendMessage(message);
           entityManager.merge(message.getFrom());
           }




      The code for sendMessage and receiveMessage is almost identical:


      public void sendMessage(Message message) {
           if (sentMessages == null) {
                sentMessages = new MessageFolder();
                sentMessages.setName("sent messages");
           }
           message.setFolder(sentMessages);
           sentMessages.add(message);
      }
      
      public void receiveMessage(Message message) {
           if (inbox == null) {
                inbox = new MessageFolder();
                inbox.setName("inbox");
           }
           message.setFolder(inbox);
           inbox.add(message);
      }



      To show the list of messages I use a simple Factory methods:


      @Factory(value = "sentList", scope = ScopeType.PAGE)
      public List<Message> getSentList() {
           return loggedUser.getSentMessages().getMessages();
      }
      
      @Factory(value = "inboxList", scope = ScopeType.PAGE)
      public List<Message> getInboxList() {
           return loggedUser.getSentMessages().getMessages();
      }



      As you can see receiving and sending a message is totally symmetrical. Thus, I am extremely surprised with a following scenario. I log in and senda message to myself. Then I enter the page with message lists. The just-sent message appears only in the sent, not in the inbox. But in the database everything is ok - there are two messages, one in each folder! Only when I log out and log in again, everything's fine - the message appears in both the lists.


      I tried a lot of things, but still can't find out why this happens. Can anybody help me?

        • 1. Re: Collection refreshing?
          damianharvey.damianharvey.gmail.com

          This is usually due to:



          • Not adding it correctly to the Collection; or

          • A problem with the Collection due to equals() or hashCode()



          Can you post your entity code?


          Cheers,


          Damian.

          • 2. Re: Collection refreshing?
            elnino

            Hello,


              If I understand your problem:



            •   1°) You check your messages... Ok all messages in db are here

            •   2°) You send a mail to yourself... For that, you add it the the sentMessage collection and persist it the database

            •   3°) You go back to you inbox.. The message is not here...



            3 questions:



            •   What is the scope of MessagesUI bean, it is stateless or stateful ?

            •   When you call message.getTo(), is it the same object that is returned as message.getFrom() object ?

            •   Have you got a cache level ?



            If you want to force the entityManager to go in database, you can call entityManager.refresh(user) if the mark the Cascade.REFRESH on messages list.


            But post your code... Will be easier.


            Regards,
            Paul

            • 3. Re: Collection refreshing?
              maciekpazur

              Thank you very much for reply.


              This is the code of Message entity:


              @Name("message")
              @Entity
              public class Message {
              
                   private Long id;
                   private User from;
                   private User to;
                   private String subject;
                   private String content;
                   private Date sentDate;
                   private MessageFolder folder;
              
                   @ManyToOne
                   @JoinColumn(name = "from_fk", referencedColumnName = "username", nullable = true)
                   public User getFrom() {
                        return from;
                   }
              
                   @NotNull
                   @ManyToOne
                   @JoinColumn(name = "to_fk", referencedColumnName = "username", nullable = true)
                   public User getTo() {
                        return to;
                   }
              
                   @Length(max = 200)
                   public String getSubject() {
                        return subject;
                   }
              
                   @Length(max = 2000)
                   public String getContent() {
                        return content;
                   }
              
                   public void setFrom(User from) {
                        this.from = from;
                   }
              
                   public void setTo(User to) {
                        this.to = to;
                   }
              
                   public void setSubject(String subject) {
                        this.subject = subject;
                   }
              
                   public void setContent(String content) {
                        this.content = content;
                   }
              
                   @ManyToOne
                   public MessageFolder getFolder() {
                        return folder;
                   }
              
                   public void setFolder(MessageFolder folder) {
                        this.folder = folder;
                   }
              
                   @GeneratedValue
                   @Id
                   public Long getId() {
                        return id;
                   }
              
                   public void setId(Long id) {
                        this.id = id;
                   }
              
                   public Date getSentDate() {
                        return sentDate;
                   }
              
                   public void setSentDate(Date sentDate) {
                        this.sentDate = sentDate;
                   }
              
              }

              • 4. Re: Collection refreshing?
                maciekpazur

                Paul Andreux wrote on Apr 29, 2009 18:36:


                Hello,

                  If I understand your problem:


                •   1°) You check your messages... Ok all messages in db are here

                •   2°) You send a mail to yourself... For that, you add it the the sentMessage collection and persist it the database

                •   3°) You go back to you inbox.. The message is not here...





                Ad 2. I send a mail to myself i.e. add it to both the sentMessage collection and inbox collection and persist it. When I open the page with message folders view - it's only in the sent messages folder, not in the inbox. That fact astonishes me most because I use the same methods to add it to both folders. Another weird fact is that the message is persisted in a correct way (when I run mysql and run appriopriate SELECT in the Message table, I see that there are two messages in two folders).



                When you call message.getTo(), is it the same object that is returned as message.getFrom() object ?


                Hm, it could be the reason, but I don't understand why nor how to fix it. The message.getTo() is taken from user interface (by select-one-listbox), the message.getFrom() is set to currentUser (taken from context). User class
                overrides equals and hash (they base on comparing username).


                This is the MessageUI code you asked for


                @Scope(CONVERSATION)
                @Name("messagesUI")
                public class MessagesUI {
                
                     @In(required = false)
                     private Message message;
                     
                        @In
                     private EntityManager entityManager;
                
                     @In(value = "currentUser")
                     private User loggedUser;
                
                     @In(create = true, value = "#{allUsers.resultList}")
                     @SuppressWarnings(value = { "unused" })
                     private List<User> allUsers;
                
                     public void sendMessage() {
                          message.setFrom(loggedUser);
                          message.getTo().receiveMessage(message);
                          entityManager.merge(message.getTo());
                          message.getFrom().sendMessage(message);
                          entityManager.merge(message.getFrom());
                     }
                
                     @Factory(value = "inboxList", scope = ScopeType.PAGE)
                     public List<Message> getInboxList() {
                          List<Message> inboxList = loggedUser.getInbox().getMessages();
                          return inboxList;
                     }
                
                     @Factory(value = "sentList", scope = ScopeType.PAGE)
                     public List<Message> getSentList() {
                          List<Message> sentList = loggedUser.getSentMessages().getMessages();
                          return sentList;
                     }
                
                }



                Thank you very much for your help.

                • 5. Re: Collection refreshing?
                  gardellajuan

                  Hi,


                  It's probably a problem for hibernate cache. Try this:


                  session.clear()


                  where session is hibernate session.


                  • 6. Re: Collection refreshing?
                    gonorrhea

                    In his case it would be EntityManager.clear().  I'm also wondering why is it you're using the merge() method?  This is not recommended (see my post on this or read SiA book) and is unnecessary if you're using SMPC with MANUAL flush (entities don't get detached from PC, so no need to merge()).  If you're simply trying to insert a record into the table, why not use persist()?

                    • 7. Re: Collection refreshing?
                      maciekpazur

                      Ok, I followed your advice and now I don't merge User entity, but persist Message.
                      I also added entityManager.clean() at the beginning of my getInboxList() method, but it still doesn't work. Do you have any other ideas or suggestions?


                      Thanks for any help.