10 Replies Latest reply on Sep 11, 2009 2:50 AM by Walter White

    EntityQuery enhancement

    Walter White Novice

      Hi all,


      EntityQuery objects are great, but I was wondering if there was a way to define them through annotations so that they would be automatically available with each project that inherits them or has them as a dependency.


      @EntityQueries({
      @EntityQuery(name = "User.findByEmailAddress", query = "FROM User u WHERE u.emailAddress = #emailAddress ")
      })
      @Entity
      public class User implements Serializable
      {
      
      ...
      }
      



      @Name("registerAction")
      public class RegisterAction implements Serializable
      {
        @In(name = "User.findByEmailAddress")
        protected EntityQuery<User> userQuery;
        @In
        protected String emailAddress;
      
        public boolean register()
        {
           User existingUser = userQuery.getSingleResult();
           if(existingUser != null)
             FacesContext.instance() ....
        }
      }
      



      The idea with this is that each project that extends the parent project does not have to re-declare entity queries, but it can just use them directly.


      This would require Seam to parse for the EntityQueries annotation along with EntityQuery and construct a component for each one it sees.




      What are your thoughts?



      Walter

        • 1. Re: EntityQuery enhancement
          Sylvain Catudal Newbie

          I'm not sure this is what you are asking, but it is possible to define them in the component.xml file.  You can see it in action in the contactList example included with the seam package.


          Here is an extract of the component.xml:


          <fwk:entity-query name="contacts" max-results="5">
            <fwk:ejbql>from Contact</fwk:ejbql>
            <fwk:order>lastName</fwk:order>
            <fwk:restrictions>
              <value>lower(firstName) like lower( concat( #{exampleContact.firstName}, '%' ) )</value>
              <value>lower(lastName) like lower( concat( #{exampleContact.lastName}, '%' ) )</value>
            </fwk:restrictions>
          </fwk:entity-query>
          
          



          I hope it helps.


          Sylvain

          • 2. Re: EntityQuery enhancement
            Walter White Novice

            Hi Sylvain,


            Please read my post carefully.


            I am giving an example of what I would like to see - I do not want to use XML, XML is great, but for modular projects, it violates the DRY principle as each child that inherits from a parent project would have to duplicate the XML for the entity queries.  Doesn't that seem repetitive to you?


            I split my projects up so that my end projects are as small as possible easier to maintain.  For example, if I do a website for client A and they request certain functionality, I will include certain dependencies or modules.  I do not want to copy and paste all of the entity queries I need each time, not only will that be extra work, I can run into more problems down the road at runtime and may not catch bugs until it's in production.



            Walter

            • 3. Re: EntityQuery enhancement
              Elias Ross Master

              You can define an EntityQuery in a separate object using plain Java. Like how Seam gen makes this:


              @Name("userList")
              public class UserList extends EntityQuery<User> {
              
                   private static final String EJBQL = "select user from User user";
              
                   private static final String[] RESTRICTIONS = {
                             "lower(user.email) like concat(lower(#{userList.user.email}),'%')",
                             "lower(user.number) like concat(lower(#{userList.user.number}),'%')",
                             "lower(user.passwordHash) like concat(lower(#{userList.user.passwordHash}),'%')",
                             "lower(user.username) like concat(lower(#{userList.user.username}),'%')",};
              
                   private User user = new User();
              
                   public UserList() {
                        setEjbql(EJBQL);
                        setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
                        setMaxResults(25);
                   }
              
                   public User getUser() {
                        return user;
                   }
              }




              • 4. Re: EntityQuery enhancement
                Nikos Paraskevopoulos Novice

                Hi Walter,


                SEAM does provide a plugin mechanism for the feature you ask. See Configuring Seam and packaging Seam applications (Chapter 29 in SEAM 2.1.1 docs) section Deploying custom resources (10 in 2.1.1 docs). It describes how to plug in the class scanning component and have a piece of your code executed.

                • 5. Re: EntityQuery enhancement
                  Walter White Novice

                  Hi Nikos,


                  Thanks, I actually am looking at the latest and greatest docs and see that under Custom Resources.  This is the trick I am looking for.



                  Thank you very much for your response.


                  I hope to post some sample code in a few weeks and hopefully get it integrated into Seam so that it could be used much like the @NamedQuery in Entity classes.



                  Walter

                  • 6. Re: EntityQuery enhancement
                    Walter White Novice

                    Hi,


                    I have a working version, is there a good way for me to post the source code?  It has EL and this is complaining about containing certain character.


                    There is an EntityQueryScanner which handles all classes annotated with @EntityQueries.  It creates all the EntityQuery component and stores all the parameters in the application context properties.  Then there are 2 annotations @EntityQueries and @EntityQuery.  These work almost identically to @NamedQueries and @NamedQuery.


                    In my domain classes that need re-usable queries, I use @EntityQueries and @EntityQuery as needed to define those and then the component will be created and injected in the proper place when needed.



                    How should I post code?



                    Walter

                    • 7. Re: EntityQuery enhancement
                      Walter White Novice

                      Hi all,


                      The custom annotations and scanner did work, but I believe I had some issues with storing the entity queries in the application scope.  Even though the query should have gotten a new instance of the EntityManager, I believe the old one was being referenced causing an IllegalStateException - EntityManager is closed.


                      The simplest and cleanest way without hacking the seam framework and startup is to use components.xml in META-INF of each project and declare the queries there, I don't have type safety, but perhaps a future release of Seam can support EntityQuery annotations in the Entity class.



                      Walter

                      • 8. Re: EntityQuery enhancement
                        Piotr Steininger Newbie

                        Walter,


                        I think this is a really good idea, in fact I wanted to officially propose it, but first I wanted to find out if anyone else thought along the same lines.


                        My motivation for it is to reduce XML dependence. Seam and its annotations go a really long way to reduce the XML burden. Why not go further and allow creating entity-home and entity-query components with annotations.
                        After reading you post I feel like there are more reasons for such enhancements.


                        I will try and see if there is a JIRA out there already, if not I'll open one and post the link here.


                        I can actually do some of the work on developing this too.


                        Thanks,


                        Piotr

                        • 10. Re: EntityQuery enhancement
                          Walter White Novice

                          Piotr,


                          Cool, I appreciate your filing the feature request as it was something I was meaning to do.  Thanks for the positive feedback.


                          The other addition I would like to see is being able to references those entity queries with some sort of type safety:


                          If you need to inject these queries in a servlet filter (I am doing this in several cases), I am doing this:




                          Components.getInstance("User_findByEmailAddress")



                          Is there some way to tie the name of the entity query back to the entity query so you can reference it directly?






                          Components.getInstance(User_findByEmailAddress)








                          That way, if you mistype it, you get the error at compile time.



                          That is probably more of a Java question and less a Seam question.




                          Walter