1 2 3 Previous Next 36 Replies Latest reply on Sep 18, 2006 3:56 AM by trouby

    Entities with one/many_to_many relationships and SEAM

    trouby

      Hey guys,

      I was wondering,

      Assuming I have an entity with one_to_many relationship, i.e:

      class X {
       String name;
       Collection<Y> yList;
      
       @Column(name="NAME")
       public long getName() {
       return name;
       }
      
       public void setName(String name) {
       this.name = name;
       }
      
      
       @OneToMany(mappedBy="x")
       public Collection<Y> getyList() {
       return yList;
       }
      
       public setYList(Collection<Y> yList) {
       this.yList = yList;
       }
      }
      



      Assuming I'd like to build some web GUI for class X, but except simple fields (such as name) I'd also like to set multiple Y entities to the collection of the X class through a WEB interface,

      Does Seam supports this easily? or i'll have to create a 'multiple selectbox' and pass IDs of Y entities, load the Y entities and set them into the collection by myself?

      Thanks a lot,

      Asaf.

        • 1. Re: Entities with one/many_to_many relationships and SEAM
          pmuir

          Look at the SelectItems thread, it discusses support for selectitems and contains links to a couple of SelectItems implementations (but I don't think either of them are finalised).

          I'll try to get mine packaged properly over the next day or two and I may alter the API.

          • 2. Re: Entities with one/many_to_many relationships and SEAM
            trouby

            What? this one?
            http://www.jboss.com/index.html?module=bb&op=viewtopic&t=78323


            These annotations are nice, but I'd like to see (if possible) a demonstration of multiple selection of objects, and not only values out of a collection.



            Cheers.

            • 3. Re: Entities with one/many_to_many relationships and SEAM
              pmuir

              I'm sorry, I'm not quite sure what you mean.

              The @SelectItems annotation (mine, not Jim's) in concert with the EntityConverter allows you to select multiple objects (from a generated list) and set them 'directly' (via the value attribute) as a collection on any object.

              The only caveat is that the objects being selected MUST be entities which have been previously persisted (as it uses the @Id annotation as the identifier). I don't think it will work for composite foreign keys either.

              Othewise you'll need to write a converter for that specific case. I've got some ideas for a non-entity generic converter but tbh I can't really think of many situations where a combination of PAGE scope and Strategy.INDEX or Strategy.STRING don't work.

              So you can do

              <h:selectManyListbox value="#{x.yList} converter="org.jboss.seam.EntityConverter">
               <f:selectItems value="#{yList}" />
              </h:selectManyListbox>
              


              @Name("yLister")
              @Stateless
              public class YListerBean implements YLister {
              
               @SelectItems
               private List<Y> yList;
              
               @In(create=true)
               private EntityManager em;
              
               @Factory("yList")
               public void buildYList() {
               yList = em.createQuery("select y from Y y").getResultList();
               }
              
              }
              


              where YLister is an interface declaring public void buildYList() and the entity classes x and y are as you describe and there is a FormActionBean for loading x.

              • 4. Re: Entities with one/many_to_many relationships and SEAM
                trouby

                Hey,

                This is cool enough,

                Is there any example which implement this annotation?

                If not yet, will you post it to the Wiki?


                Thanks

                • 5. Re: Entities with one/many_to_many relationships and SEAM
                  pmuir

                  Yes, look at the wiki ;) (under Components) or http://jroller.com/page/pmuir?entry=selectitems_revisited has an example (basically a completeimplementation of what I wrote below), some documentation. To use just take the jar and place in your ear.

                  • 6. Re: Entities with one/many_to_many relationships and SEAM
                    trouby

                    Hey,

                    back to this,
                    When I try to use it, I get the following error message generated by JSF:
                    "Validation Error: Value is not valid"


                    What is I think is that JSF verifies that selected items are members of collection returned by f:selectItems tag.
                    So after conversion of the bean value JSF probably calls equals on every element of the collection and the converted.

                    Anyway, as it seems. The loaded entity by EntityConverter does not match the items within the collection of selectItems tag,


                    Is that possible? or maybe it is something else? I can't make it work anyway :-/

                    Thanks

                    • 7. Re: Entities with one/many_to_many relationships and SEAM
                      pmuir

                      Yes you are right. See http://java.sun.com/javaee/javaserverfaces/1.1_01/docs/api/javax/faces/component/UISelectOne.html for example.

                      I hadn't come across it as I always override the equals methods of entities to compare on id equality (if the object is set, otherwise fallback on object equality).

                      A drawback the EntityConverter for which I can see no work around (you get the Entities from two different EntityManager instances [1]). So, you could either add an equals method (as on the example ClientType) or you could look at the alternive index or String strategies. Or wait for someone to come up with a @SelectItemsSelection annotation.

                      [1] I couldn't get them from the SeamManaged Persistence Context as it caused entities to become detached when using Container Managed Transactions.

                      • 8. Re: Entities with one/many_to_many relationships and SEAM
                        trouby

                        Hey,

                        Yeah, I understand....



                        Well, I added to the entity the following method:

                        @Override
                         public boolean equals(Object obj) {
                         if (!(obj != null && obj instanceof TargetSystem))
                         return false;
                         TargetSystem ent = (TargetSystem) obj;
                         if (this.targetSystemId.equals(ent))
                         return true;
                         return false;
                         }
                        


                        Still getting the 'Validation Error: Value is not valid ' message....


                        Am I missing anything?



                        • 9. Re: Entities with one/many_to_many relationships and SEAM
                          trouby

                          Nah, my mistake, I've compared an ID with an entity...


                          That works, but anyway I was wondering,

                          Is there going to be any standard of these? We alreayd have two types of SelectItems annotation.... What SEAM team is going to decide about this?


                          Thanks guys.

                          • 10. Re: Entities with one/many_to_many relationships and SEAM
                            trouby

                            Hey,

                            Btw, going a seocnd for the original subject of this post ;)

                            Is there any example of using multiple selection tags such as:
                            'selectManyListbox' ?

                            I'd like to see a collection set automatically and not a specific entity,

                            As I understand, the SelectItems annotation and the entityconverter together supports multiple selections and set selected items directly into the list?

                            Is there any example for this?

                            I tried the following code:

                            <h:selectManyListbox id="xx" size="10" value="#{x.yList}" converter="org.jboss.seam.EntityConverter" required="true">
                             <f:selectItems value="#{yList}"/>
                             </h:selectManyListbox>
                            




                            But I always get 'Validation Error: Value is not valid', also I can assure that EntityConverter does not even try to convert the values to objects...


                            Thanks a lot,

                            Asaf.

                            • 11. Re: Entities with one/many_to_many relationships and SEAM
                              pmuir

                              I'll double check and I'll try to write an example tonight or tomorrow.

                              • 12. Re: Entities with one/many_to_many relationships and SEAM
                                trouby

                                Sure,

                                At the moment I switched to multipleSelection, I've noticed that EntityConverter does not even try to load the entity...


                                Will wait for some testings / examples :)

                                Thanks a lot!

                                Asaf.

                                • 13. Re: Entities with one/many_to_many relationships and SEAM
                                  pmuir

                                  I've put up a new version which includes a selectMany example. I haven't got it working perfectly, you have to specify the class name of the entity as an attribute of the converter [1], and there is a small fix. Let me know if it works for you or not.

                                  [1] The converter knows which class of object to load by looking at the value attribute of the select tag. When it's directly pointing at an entity object it can work out what class to use from that. When it's a list it's not so simple - I think a sensible default could be come up with (e.g. all objects in the list are the same type then use that, otherwise complain) and also a useful error message.

                                  • 14. Re: Entities with one/many_to_many relationships and SEAM

                                    I hope this is not too off-topic, but I'm having some difficulty getting my Seam app up with @ManyToMany (though I suspect it's not really a Seam problem).

                                    I've got two entity beans, User and Group, with a many-to-many relationship where User is the owner. I have a GroupManagerBean class which is a stateful session bean where I'd like to have a create() method that will create a new group with an initial user. I'm trying to figure out exactly how to annotate the classes and do the data update; my first few attempts haven't worked and I was hoping somebody could offer some advice about how to get this right: cascade types, idioms for object creation and update, etc.

                                    I've tried to extract the relevant code snippets below. Pointers on how to do this or to previous discussions of this topic gratefully accepted.

                                    Thanks.

                                    User.java

                                    @Entity
                                    @Name("user")
                                    @Role(name="currentUser", scope=SESSION)
                                    @Table(name="USERS")
                                    public class User implements Serializable {
                                     ...
                                     private Set<Group> groups = new HashSet<Group>();
                                     @ManyToMany(cascade=CascadeType.ALL)
                                     @JoinTable(name="USER_GROUP",
                                     joinColumns={@JoinColumn(name="USER_ID")},
                                     inverseJoinColumns={@JoinColumn(name="GROUP_ID")})
                                     public Set<Group> getGroups() {
                                     return groups;
                                     }
                                     public void setGroups( Set<Group> groups ) {
                                     this.groups = groups;
                                     }
                                    }
                                    



                                    Group.java

                                    @Entity
                                    @Name("group")
                                    @Table(name="GROUPS")
                                    public class Group implements Serializable {
                                     ...
                                     @ManyToMany(cascade=CascadeType.ALL)
                                     @JoinTable(name="USER_GROUP",
                                     joinColumns={@JoinColumn(name="USER_ID")},
                                     inverseJoinColumns={@JoinColumn(name="GROUP_ID")})
                                     public Set<Group> getGroups() {
                                     return groups;
                                     }
                                     public void setGroups( Set<Group> groups ) {
                                     this.groups = groups;
                                     }
                                    }
                                    


                                    GroupManagerBean.java

                                    @Stateful
                                    @Name("groupManager")
                                    @LoggedIn
                                    public class GroupManagerBean implements GroupManager, Serializable {
                                     ...
                                     public void create() {
                                     group = new Group();
                                     group.setGroupname( newGroupname() );
                                     orgmobDatabase.persist( group );
                                     // User owns the bidirectional many-to-many relationship with Group
                                     user.getGroups().add( group );
                                     orgmobDatabase.merge( user );
                                     orgmobDatabase.refresh( group );
                                     // PROBLEM:
                                     // I thought that group.getUsers() would contain user, but it doesn't!
                                     //debug
                                     log.debug( "for user "+user+" created group: "+group);
                                     log.debug( "user "+user+" has "+user.getGroups().size()+" groups");
                                     log.debug( "group "+group+" has "+group.getUsers().size()+" users");
                                     for ( Group g : user.getGroups() ) {
                                     log.debug( "a group for user "+user+": "+g);
                                     }
                                     for ( User u : group.getUsers() ) {
                                     log.debug( "a user for group"+group+": "+u);
                                     }
                                     }
                                    }
                                    



                                    1 2 3 Previous Next