1 2 Previous Next 28 Replies Latest reply on Nov 8, 2006 4:05 PM by iradix Go to original post
      • 15. Re: EntityManger-per-user-session...
        iradix

        1) You are outjecting your parent without an explicit scope, I can't remember the rules but I think an entity will default to event.

        2) No, I would say that mixing and matching the two is not a good idea. I can't say for sure why your em isn't injecting properly, but play around with it. It does work and it seems like you've got the right idea.

        • 16. Re: EntityManger-per-user-session...
          bkyrlach

           

          "iradix" wrote:
          1) You are outjecting your parent without an explicit scope, I can't remember the rules but I think an entity will default to event.[/quote

          I thought outjection observed the entities scope. In this case, Parent is annotated with @Scope(ScopeType.SESSION)

          "iradix" wrote:
          2) No, I would say that mixing and matching the two is not a good idea. I can't say for sure why your em isn't injecting properly, but play around with it. It does work and it seems like you've got the right idea.


          There's no error messages or anything in the log. I'm basically reduced to banging my head against my CRT. :$


          • 17. Re: EntityManger-per-user-session...
            bkyrlach

            The above is an example of why not to post when you're frustrated. Stupid not closing the quote tag properly. :(

            • 18. Re: EntityManger-per-user-session...
              bkyrlach

              Actually though, the debug page shows that the Parent is in the session context. It's just not getting injected into the ChildListBean correctly.

              • 19. Re: EntityManger-per-user-session...
                iradix

                From the docs

                By default, entity beans are bound to the conversation context. They may never be bound to the stateless context.


                The scope specified in the bean is the scope it will be outjected to if it is created through seam (i.e. @In(create = true)). When using @Out the default rules are observed unless you have a scope defined.

                I'd suggest you keep playing with you em. If it works in the first bean you know it's defined correctly. Perhaps your second bean isn't getting intercepted.

                • 20. Re: EntityManger-per-user-session...
                  bkyrlach

                  Doh... I really am an r-tard.

                  Yeah, I forgot to annotate ChildListBean with @Interceptors(SeamInterceptor.class)

                  • 21. Re: EntityManger-per-user-session...
                    gavin.king

                    But that stuff in ejb-jar.xml, don't use the @Interceptors annotation anymore, its ugly.

                    • 22. Re: EntityManger-per-user-session...
                      bkyrlach

                      Okay... so why doesn't this work...

                      First I create a parent and outject it to the Session context...

                      View...

                       <h:form>
                       <table>
                       <tr>
                       <td>Name:</td>
                       <td><h:inputText value="#{newParent.name}"/></td>
                       </tr>
                       <tr>
                       <td>Submit:</td>
                       <td><h:commandButton action="#{parentActions.createParent}"/></td>
                       </tr>
                       </table>
                       </h:form>
                      


                      Model...

                      @Entity
                      @Name("parent")
                      @Scope(ScopeType.SESSION)
                      @Role(name="newParent", scope=ScopeType.EVENT)
                      public class Parent implements Serializable
                      {
                      ...
                      ...
                      ...
                       @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="parent")
                       public List<Child> getChildren()
                       {
                       return children;
                       }
                       public void setChildren(List<Child> children)
                       {
                       this.children = children;
                       }
                      ...
                      ...
                      ...
                      }
                      


                      Action...

                      package sample.business.pc;
                      
                      import javax.ejb.Stateless;
                      import javax.interceptor.Interceptors;
                      import javax.persistence.EntityManager;
                      import javax.persistence.PersistenceContext;
                      
                      import org.jboss.seam.annotations.In;
                      import org.jboss.seam.annotations.Name;
                      import org.jboss.seam.annotations.Out;
                      import org.jboss.seam.contexts.Contexts;
                      import org.jboss.seam.ejb.SeamInterceptor;
                      
                      import sample.model.pc.Parent;
                      
                      @Stateless
                      @Name("parentActions")
                      @Interceptors(SeamInterceptor.class)
                      public class ParentActionsImpl implements ParentActions
                      {
                       @In(create=true)
                       EntityManager em;
                      
                       @Out(required=false)
                       Parent parent;
                      
                       @In(required=false)
                       Parent newParent;
                      
                       public String createParent()
                       {
                       em.persist(newParent);
                       parent = newParent;
                       return "/pc/viewer.xhtml";
                       }
                      
                       public Parent getParent(Long id)
                       {
                       return em.find(Parent.class, id);
                       }
                      }
                      


                      And then go to create a child...

                      View...

                       <h:form>
                       <table>
                       <tr>
                       <td>Name:</td>
                       <td><h:inputText value="#{child.name}"/></td>
                       </tr>
                       <tr>
                       <td>Submit:</td>
                       <td><h:commandButton action="#{childActions.createChild}"/></td>
                       </tr>
                       </table>
                       </h:form>
                      


                      Model...

                      @Entity
                      @Name("child")
                      @Scope(ScopeType.CONVERSATION)
                      public class Child implements Serializable
                      {
                      ...
                      ...
                      ...
                       @ManyToOne
                       public Parent getParent()
                       {
                       return parent;
                       }
                       public void setParent(Parent parent)
                       {
                       this.parent = parent;
                       }
                      ...
                      ...
                      ...
                      }
                      


                      Action...

                      package sample.business.pc;
                      
                      import java.io.Serializable;
                      import java.util.ArrayList;
                      import java.util.List;
                      
                      import javax.ejb.Remove;
                      import javax.ejb.Stateful;
                      import javax.interceptor.Interceptors;
                      import javax.persistence.EntityManager;
                      
                      import org.jboss.seam.ScopeType;
                      import org.jboss.seam.annotations.Begin;
                      import org.jboss.seam.annotations.Destroy;
                      import org.jboss.seam.annotations.End;
                      import org.jboss.seam.annotations.In;
                      import org.jboss.seam.annotations.Name;
                      import org.jboss.seam.annotations.Out;
                      import org.jboss.seam.annotations.Scope;
                      import org.jboss.seam.ejb.SeamInterceptor;
                      
                      import sample.model.pc.Child;
                      import sample.model.pc.Parent;
                      
                      @Stateful
                      @Name("childActions")
                      @Scope(ScopeType.CONVERSATION)
                      @Interceptors(SeamInterceptor.class)
                      public class ChildActionsImpl implements ChildActions, Serializable
                      {
                       @In(create=true)
                       EntityManager em;
                      
                       @In
                       Parent parent;
                      
                       @In(required=false)
                       @Out(required=false)
                       Child child;
                      
                       @In(create=true)
                       ParentActions parentActions;
                      
                       @Begin
                       public String preCreateChild()
                       {
                       parent = parentActions.getParent(parent.getId());
                       return "/pc/createChild.xhtml";
                       }
                      
                       @End
                       public String createChild()
                       {
                       child.setParent(parent);
                       List<Child> children = parent.getChildren();
                       if(children == null)
                       {
                       children = new ArrayList<Child>();
                       }
                       children.add(child);
                       parent.setChildren(children);
                       return "/pc/viewer.xhtml";
                       }
                      ...
                      ...
                      ...
                      }
                      


                      So, when preCreate is called, I call ParentActions and get them to return me an attached instance of the current Parent using em.find(Parent.class, parent.getId()); This is inside a long runnig conversation, so you tell me that the same EntityManager instance is used for the entire conversation. Then, after injecting the newly created Child, I set it's parent, add it to the parents collection, and now I'm supposing the following should happen...

                      EntityManager discovers Parent is dirty and goes to merge it. Since Parents child collection is marked as cascade all, all of parents child elements should also be persisted, and my new child should be visible in the database. This isn't what's happening though.

                      Help?

                      • 23. Re: EntityManger-per-user-session...
                        bpatters

                        I don't see you creating the child anywhere and merging it into the entitymanager.

                        • 24. Re: EntityManger-per-user-session...
                          iradix

                          Your on the right track, now you're starting to get how the EM works and it's time to bone up on your hibernate docs. Look into how collections are handled. A tip, you can't set a new List into your object after it's retrieved.

                          • 25. Re: EntityManger-per-user-session...
                            bkyrlach

                            See, this still leaves some key questions unanswered.

                            1) I've updated my ChildActions thusly...

                             @In @Out
                             Parent parent;
                            
                             @Begin
                             public String preCreateChild()
                             {
                             parent = parentActions.getParent(parent.getId());
                             return "/pc/createChild.xhtml";
                             }
                            
                             @End
                             public String createChild()
                             {
                             child.setParent(parent);
                             parent.getChildren().add(child);
                             return "/pc/viewer.xhtml";
                             }
                            


                            Which _mostly_ works the way I want. The one problem being that this method of adding the children to the parent doesn't take into account annotations on the children collection on parent which has (now) an @OrderBy("name"). By doing the following...

                            em.persist(child);
                            em.flush();
                            em.refresh(user);
                            


                            I can get around this, but that doesn't seem like it's the right way.

                            2) For my pre/edit action methods...

                             @Begin
                             public String preEditChild(Child child)
                             {
                             parent = parentActions.getParent(parent.getId());
                             this.child = child;
                             return "/pc/editChild.xhtml";
                             }
                            
                             @End
                             public String editChild()
                             {
                             return "/pc/viewer.xhtml";
                             }
                            


                            almost works, but again, I find that I have to change the line...

                            this.child = child;
                            


                            to this...

                            this.child = em.merge(child);
                            


                            Which also seems bad. I'm guessing I can add a helper method on ChildListBean similar to the method on UserActions that does a find on Activity, but again... all of this magically works when I use a session scoped EM because it doesn't forget these entities so quickly. I guess if it needs be done, then fine. It just seems a little ugly.

                            • 26. Re: EntityManger-per-user-session...
                              iradix

                              It doesn't need to be done. You have to merge your child because it was retrieved before you began your conversation. If not, it wouldn't be available to pass into your method annotated with @Begin. If you are conscious of your conversation lifecycle and the fact that your persistence context is tied to it, you won't have to merge.

                              • 27. Re: EntityManger-per-user-session...
                                bkyrlach

                                Well, thanks for all your help. I guess I'll go read more documentation.

                                • 28. Re: EntityManger-per-user-session...
                                  iradix

                                  No problem. It's frustrating at first, but once you get the feel for thinking about things in terms of conversations it can make many complicated tasks much easier (in my opinion at least).

                                  1 2 Previous Next