6 Replies Latest reply on Sep 28, 2010 4:10 PM by padrino121

    Restrictions not being applied when running EntityQuery from Action

    padrino121

      (project based off of seam-gen sources)


      I have an action that parses an input file and builds Home objects to insert into a DB. After much trial and error I have that working fine however before insert I need to do a partial match on some of the columns to determine if the item already exists.


      To check if the item exists I'm using the List EntityQuery class to build a query, the query executes fine and I can return a full list of everything in the database however the restrictions that work from the List.xhtml are not applied when executing from the action and I get a return of everything. I checked the List object and see that the object properties are set correctly, for reference this is the List EntityQuery:




      @Name("productList")
      public class ProductList extends EntityQuery<Product> {
      
           /**
            * 
            */
           private static final long serialVersionUID = -7954123275209781511L;
      
           private static final String EJBQL = "select product from Product product";
      
           private static final String[] RESTRICTIONS = {
                     "lower(product.manufacturer) like lower(concat(#{productList.product.manufacturer},'%'))",
                     "lower(product.partnumber) like lower(concat(#{productList.product.partnumber},'%'))",
                     "lower(product.classcode) like lower(concat(#{productList.product.classcode},'%'))",
                     "lower(product.subclass) like lower(concat(#{productList.product.subclass},'%'))",};
      
           private Product product = new Product();
      
           public ProductList() {
                setEjbql(EJBQL);
                setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
                setMaxResults(25);
           }
      
           public Product getProduct() {
                return product;
           }
      }




      In my action I do the following to configure the restrictions, right now it runs the query with no restrictions no matter the configuration, I've tried to build the restriction array directly in code and apply them but they also aren't used so I'm focusing on what looks like the proper way to do it. The Product object in ProductList has the properties set properly when the query is executed but there is no where clause added to the SQL, is there something I need to do in code to get the query to pickup the restrictions like it does when running from ProductList.xhtml



                  ProductList productList = new ProductList();
              Product currentProduct = productList.getProduct();
                
              currentProduct.setManufacturer(newProduct.getManufacturer());
              currentProduct.setPartnumber(newProduct.getPartnumber());
              currentProduct.setClasscode(newProduct.getClasscode());
              currentProduct.setSubclass(newProduct.getSubclass());






        • 1. Re: Restrictions not being applied when running EntityQuery from Action
          padrino121

          I've spent the whole day on this without any measurable progress. Based on the observed behavior and the fact that I can read the properties myself I must be very close to the solution but it continues to escape me.

          • 2. Re: Restrictions not being applied when running EntityQuery from Action
            lvdberg

            Hi,


            EntityQuery builds the WHERE-clause with the restictions. Whenever the restriction results in a null, it will not be included. Because you mention that it always returns the full query, I think you have a conversation problem, or better stated: the lack of it. To be able to use the restrcitions, they must be in scope when you make the request/fire the query. Place the comnponents in conversation scope, start a long-running conversation and try again.


            Leo

            • 3. Re: Restrictions not being applied when running EntityQuery from Action
              padrino121

              Hi Leo,


              You confirmed something I suspected and it highlights my apparent lack of understanding of scope in Seam. I explicitly defined my components in conversation scope and that didn't seem to help but I suspect I don't know enough still.


              As a partial fix I manually wrote EJBQL with my where clauses defined to get over that hump but I think I have scope issues all over the place since I have a similar issue with my Home component in the action. I pass it as an @In parameter and can persist a new row to the DB by using the setters to define the row but when I try and setup a new instance (using clearInstance/getInstance, or simply defining the setters again) to persist another row (in for loop) it blows up the second time with null pointers to the values I set things to within my action.


              I'm beating my head against the wall and running on little to no sleep but just can't seem to get everything lined up properly.

              • 4. Re: Restrictions not being applied when running EntityQuery from Action
                lvdberg

                Hi,


                defining the components' scope as conversation is just one part, but you must a a long conversation to make use of it.


                So somewhere in your code you need the @Begin and when you (for example) persist you need the @End. This can also be achieved by adding an element to pages.xml.xml where you state that you want a lon-running conversation.


                Although the Seam documentation is readable, I suggest buying the Seam In Action book, which contains really extensive explanation about this subject.


                Leo



                • 5. Re: Restrictions not being applied when running EntityQuery from Action
                  njrich28

                  Looking at the code


                          ProductList productList = new ProductList(); // productList is not a Seam component instance
                          Product currentProduct = productList.getProduct();
                           
                          currentProduct.setManufacturer(newProduct.getManufacturer());
                          currentProduct.setPartnumber(newProduct.getPartnumber());
                          currentProduct.setClasscode(newProduct.getClasscode());
                          currentProduct.setSubclass(newProduct.getSubclass());
                  



                  this doesn't look like a scoping/conversation problem.


                  I think the problem is that productList in the code above isn't a Seam component instance because it was created with the new operator - it's just a plain old java object. Because you just created a new object (without letting Seam get involved) it won't exist in any scope so when you reference #{productList.product.*} in your code you're actually referring to a different instance of the ProductList (with a new empty product in it). Try


                          ProductList productList = (ProductList) Component.getInstance("productList");
                          Product currentProduct = productList.getProduct();
                           
                          currentProduct.setManufacturer(newProduct.getManufacturer());
                          currentProduct.setPartnumber(newProduct.getPartnumber());
                          currentProduct.setClasscode(newProduct.getClasscode());
                          currentProduct.setSubclass(newProduct.getSubclass());
                  



                  This will let Seam create an instance of the component for you and put it in whichever scope you choose - that way the productList you are using in your action is the same as the one you reference in the productList itself.


                  As a general rule don't use the new operator to get hold of instances of your components. Either @Inject them or use Component.getInstance(...), whichever is more appropriate. I think you allude to this above where you are talking about injecting a home component.

                  • 6. Re: Restrictions not being applied when running EntityQuery from Action
                    padrino121

                    Neil Richardson wrote on Sep 28, 2010 12:26:


                    This will let Seam create an instance of the component for you and put it in whichever scope you choose - that way the productList you are using in your action is the same as the one you reference in the productList itself.

                    As a general rule don't use the new operator to get hold of instances of your components. Either @Inject them or use Component.getInstance(...), whichever is more appropriate. I think you allude to this above where you are talking about injecting a home component.


                    Thanks for the pointer, this definitely helps as I can now see the component and change it's scope based on what's appropriate. I'm still having some issue with it picking up the properties but at this point I suspect it is a small detail.


                    This same general issue seems related to the current challenge I am focusing on for the Home component. I am wiring  the Home component and passing it in via @In. I can populate it in my action (action scoped to conversation per earlier discussion) and persist it once. After that things get bad as I have tried any number of ways to reuse the Home component via clearInstance, Component.getInstance, removing from conversation then readding using Context, etc. all without any luck. Once I persist the Home component one time I can't seem to reuse it to write another row to the database, I end up with NullPointers for the component properties.