1 2 Previous Next 15 Replies Latest reply on Aug 28, 2006 4:16 PM by sjmenden

    Merging objects problems.

    sjmenden

      I have a form which a user can input a group name and other group information. The EJB3 backing the form persists/merges the Injected Group object given there are no errors.

      My Problem:

      First I could not get em.persist(group) to persist more than one Group object after a form submit because of org.hibernate.PersistentObjectException: detached entity passed to persist:....

      So, then I started using em.merge(group) on the Group object, which fixed the previous problem, but led to another. When I am creating two different groups by submitting the form twice with different information, the entity manager appears only update the same group by the console output:

      Output after em.merge(group) after the form submit the first time:

      16:11:26,634 INFO [RegisterGroupAction] Registered new Group asdf with id: 4
      


      Output after em.merge(group) after the form submit the second time with different data.
      16:11:41,496 INFO [RegisterGroupAction] Registered new Group blah with id: 4
      


      This is not the behavior I want, I want a new Group object to be persisted every time the user submits a new group form, so I should be seeing the id incremented, not staying the same, how can I do this.


      @Stateless
      @Name("registerGroup")
      public class RegisterGroupAction implements RegisterGroup {
      
       @In(create=true) @Out @Valid
       private Group group;
      
       @PersistenceContext
       private EntityManager em;
      
       @Logger
       private Log log;
      
       public String register() {
       List existing = em.createQuery("select name from Group where name = :name")
       .setParameter("name", group.getName())
       .getResultList();
       if (existing.size()==0) {
       group = em.merge(group);
       //em.persist(group);
      
       FacesMessages.instance().add("Group successfully created");
       log.info("Registered new Group #{group.name} with id: " + group.getGroupId());
       return "/showGroup.jsp";
       } else {
       FacesMessages.instance().add("Group name already exists, please choose another");
       return null;
       }
       }
      }
      


        • 1. Re: Merging objects problems.
          bfo81

          em.persist should work. But there are some mistakes in your architecture. If there is a underlying JSF page that uses the "group" component, you need to make the bean a Stateful Bean. Furthermore, the PersistenceContext needs to be EXTENDED. Otherwise the entity will get detached, and that's the reason why persisting failed.

          Have a look at how persistence works:
          http://www.jboss.com/index.html?module=bb&op=viewtopic&t=88460

          • 2. Re: Merging objects problems.
            mrohad

            question regarding PersistenceContextType.EXTENDED
            is it possible to explictly deattach the Entities some how?

            I am selecting the entitybeans I want ,then showing them and their relationship entitybeans in a JSF table ,then I would like to store them in a cache and deattache them , is it possible?

            • 3. Re: Merging objects problems.
              raja05

              sjmenden, try removing the @Out from the group field declaration. What you are doing (after the first time the insert happens) is that you are outjecting that object into the "group" field which gets used by the subsequent jsps. So what you are actually doing is only an update as the first object is what is fed into the jsps subsequently, not any new Group object.

              • 4. Re: Merging objects problems.
                sjmenden

                I see what I'm doing wrong, but that begs another question, how do I accomplish what I want to accomplish.

                Shouldn't Registering a Group be stateless?

                I want for the user to register a group, and be redirected to a page which displays that group, and allows the user to modify that group ect., which is why I am outjecting the Group.

                How do I do that best?

                • 5. Re: Merging objects problems.
                  raja05

                   

                  "sjmenden" wrote:

                  I want for the user to register a group, and be redirected to a page which displays that group, and allows the user to modify that group ect., which is why I am outjecting the Group.

                  This should work with your current code and which I thought was the problem you mentioned in the original post. You are modifying the group that got created, so it makes sense to just do updates to that object and not create new ones. I thought your original post said that you were creating 2 different group objects and they were updating the same one (the one that got created first).


                  • 6. Re: Merging objects problems.
                    bfo81

                    No, he wants to create a new group and uses another group as a template. That's how I understood it (I hope there's no misunderstanding ;)).

                    sjmenden, are you sure you read the thread I posted above? It's very important to understand the 4 states entities can have. If you want to create a new group with a new id, then you really need Group newGroup = new Group();. When you want to merge an existing managed or detached entity (which you retrieved e.g. via em.find), it always keeps its id.

                    • 7. Re: Merging objects problems.
                      bfo81

                      There's something important I forgot to mention:

                      You might think that a group gets newly created here:

                      @In(create=true) @Out @Valid
                       private Group group;


                      But that's wrong, it already exists:
                      org.hibernate.PersistentObjectException: DETACHED (!!!!!!!!!!!!!!) entity passed to persist:

                      group is definitely a MANAGED object, that was read via em.find or em.createQuery()... and then got DETACHED during Seam bijection. The only entites that are able to be persisted are those of state NEW/TRANSIENT or REMOVED. That's why em.persist() didn't work. Then you tried em.merge(), which led to an update of an existing group instead of creating a new one.


                      And the second thing: I didn't exactly understand what's behind your register bean (I'd be interested in the JSF file). Only then we can say if the bean should be stateless or stateful ;).

                      • 8. Re: Merging objects problems.

                         

                        "mrohad" wrote:
                        question regarding PersistenceContextType.EXTENDED
                        is it possible to explictly deattach the Entities some how?

                        I am selecting the entitybeans I want ,then showing them and their relationship entitybeans in a JSF table ,then I would like to store them in a cache and deattache them , is it possible?


                        yes. call em.clear();

                        from the API docs...

                        clear()
                        Clear the persistence context, causing all managed entities to become detached.


                        • 9. Re: Merging objects problems.
                          sjmenden

                          Thank you for the replies, I don't really want to use the other group as a template let me clarify my goals here again:

                          All I want is a simple page that allows a person to register a group, after registering the group, the EJB3 redirects to page that displays that group with links to edit the group, to add users to the group and so forth.

                          There is a link on my left navigation for the page createGroup.jsp, when the user clicks that link, it will display a form to enter information for the group and a button to create it. After creating one group, which works, and I click the creatGroup.jsp link again, it remembers the previous values, I am assuming because my Group entity bean has a SESSION scope. But I guess my RegisterGroup stateless bean is also remembering the group, thus updating on merge or failing on persist the 2nd time I try to create a new group.

                          So to reiterate what I want is simply to accomplish is for a user to be able click my createGroup.jsp link and each time be able to create a new and unique group then be redirected to a page that more formally displays that group.

                          • 10. Re: Merging objects problems.
                            robjellinghaus

                            You want to be using conversation scope, not session scope. This is pretty much exactly what conversations are for. The CreateGroup action should have @Begin on the createNewGroup method, and the Group component should be conversation-scoped. The editing actions should all be conversation-scoped also, so they are editing only that group that was created int he conversation.

                            Then any action method that returns you to the CreateGroup page should have @End, so it clears the conversation-scoped Group.

                            Hope that helps :-) Make sure you reread the Seam documentation about conversations; this is exactly what they are for!

                            • 11. Re: Merging objects problems.
                              bfo81

                              No, your stateless bean does not keep the group since it's stateless ;). It only knows about the group cause it gets injected.

                              As I said it's quite difficult to GUESS what the problem causes. It would be better to LOOK at your code ;). But I think that you only call new Group(); once. Or you use @In(create=true) everywhere.

                              However, you need to make sure that the group is really created newly explicitely.

                              And RobJellinghaus is right, whenever beginning an action that spans multiple pages there's a bill ringing and saying, "conversation!" ;).

                              • 12. Re: Merging objects problems.
                                bfo81

                                Not a bill... a bell of course ;).

                                • 13. Re: Merging objects problems.
                                  sjmenden

                                  I will post my code to satisfy curiosity although there is not much to look at.

                                  Using Conversation scope seems very strange to me in this instance. I guess SEAM caters to a whole new realm of patterns that don't exist in the other MVC world.

                                  Registering a Group SHOULD be stateless, at least I thought so, but in this case you are saying it should be Conversational. I really don't want any other functionality in this bean at the moment except registering groups. A completely different bean will handle viewing and editing the Group.

                                  RegisterGroupAction.java:

                                  @Stateless
                                  @Name("registerGroup")
                                  public class RegisterGroupAction implements RegisterGroup {
                                  
                                   @In(create=true) @Out @Valid
                                   private Group group;
                                  
                                   @PersistenceContext
                                   private EntityManager em;
                                  
                                   @Logger
                                   private Log log;
                                  
                                   public String register() {
                                   List existing = em.createQuery("select name from Group where name = :name")
                                   .setParameter("name", group.getName())
                                   .getResultList();
                                   if (existing.size()==0) {
                                   //group = em.merge(group);
                                   em.persist(group);
                                  
                                  
                                  
                                   FacesMessages.instance().add("Group successfully created");
                                   log.info("Registered new Group #{group.name} with id: " + group.getGroupId());
                                   return "/showGroup.jsp";
                                   } else {
                                   FacesMessages.instance().add("Group name already exists, please choose another");
                                   return null;
                                   }
                                   }
                                  }
                                  



                                  registerGroup.jsp - the commandButton is only relevant I think
                                  ...
                                  ...
                                  ...
                                  <h:commandButton type="submit" value="Greate Group" action="#{registerGroup.register}"/>
                                  ...
                                  ...
                                  ...
                                  




                                  • 14. Re: Merging objects problems.
                                    sjmenden

                                    And I just removed the @Out annotation to the Group object, but I'm still getting the Detached Exception when trying to persist a group twice.

                                    Let me explain what I'm seeing. I click on registerGroup.jsp brings me to a page, I input a name and click register, then I get redirected to a page which displays the Group, that is all great.

                                    NOW, I click on registerGroup.jsp again and I don't get a fresh form, but I get the form with the old group I just registered, well, I change the name, and I get the exception. So I am assuming that the Group lives in Session scope, and that I need a separate EVENT scope for this particular instance?

                                    1 2 Previous Next