9 Replies Latest reply on Jun 12, 2003 5:11 AM by tdang

    Problem with 1-Many Relationships

    tdang

      Hi all,

      I have 2 ejbs: Category and Product. They have the 1-Many Relationship. I could deploy my beans and it runs well, until I add a product to a category like this:

      public void addProduct(String category, String product)
      throws FinderException, CreateException {
      try {
      Category c = createCategoryHome().findByPrimaryKey(category);
      Product p = createProductHome().create(product);

      c.getProductBeans().add(p);
      } catch (NamingException ne) {
      throw new EJBException(ne);
      }
      }

      I got the following errors from jboss:

      java.lang.reflect.UndeclaredThrowableException: java.rmi.ServerException: RemoteException occurred in server thread; nested exception is:
      java.rmi.ServerException: RuntimeException; nested exception is:
      java.lang.IllegalStateException: A CMR collection may only be used within the transction in which it was created

      java.rmi.ServerException: RuntimeException; nested exception is:
      java.lang.IllegalStateException: A CMR collection may only be used within the transction in which it was created
      java.lang.IllegalStateException: A CMR collection may only be used within the transction in which it was created at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:245)
      at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:220)
      at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:122)
      at org.jboss.invocation.jrmp.server.JRMPInvoker_Stub.invoke(Unknown Source)
      at org.jboss.invocation.jrmp.interfaces.JRMPInvokerProxy.invoke(JRMPInvokerProxy.java:138)
      at org.jboss.invocation.InvokerInterceptor.invoke(InvokerInterceptor.java:108)
      at org.jboss.proxy.TransactionInterceptor.invoke(TransactionInterceptor.java:77)
      at org.jboss.proxy.SecurityInterceptor.invoke(SecurityInterceptor.java:80)
      at org.jboss.proxy.ejb.StatelessSessionInterceptor.invoke(StatelessSessionInterceptor.java:111)
      at org.jboss.proxy.ClientContainer.invoke(ClientContainer.java:76)
      at $Proxy1.addProduct(Unknown Source)
      at org.eStore.test.TestMySQL.main(TestMySQL.java:21)

      I am using JBoss3.0.4

      Every help would be appreciated.

      Thanks in advance.

        • 1. Re: Problem with 1-Many Relationships
          tdang

          I forgot attach configuration files

          • 2. Re: Problem with 1-Many Relationships
            danield

            Hi tdang,

            If you execute this method you would only add a Product to a Collection and not to a Category. You should add a new Method to the Category where you can add products. Something like this:

            public void addProduct(Product p) throws Exception{
            try{
            getProducts().add(p);
            }catch(Exception e){
            }
            }

            That should do the job.

            Another workaround for accessing a Collection of Products you get from the Category is to return a Copy of the Collection. You have to add another method to the Category (example):

            public Collection getProductsTwo(){
            return new java.util.ArrayList(getProducts()):
            }

            But remember that you get only a Collection and you only work with this and not with the Category.

            • 3. Re: Problem with 1-Many Relationships
              tdang

              Hi,

              first thanks a lot for your very kind response.

              I think your new method

              public void addProduct(Product p) throws Exception{
              try{
              getProducts().add(p);
              }catch(Exception e){
              }
              }

              is very similar with mine.

              By the way, I had the same code in another project, and it works fine. Since the bean Category contains through the cmr-field productBeans a collection of products, in which product objects have EJBLocalObject type. So I think the way I did is not wrong.

              Thanks.

              • 4. Re: Problem with 1-Many Relationships
                danield

                As I wrote I'm very new to EJB and JBoss, but I think the difference is, that I add a product inside of the Category. So it has a consistent state.
                Your code will generate a new Collection and adds a product there, so the Category did not know anything about this new Product.

                Maybe, that I'm wrong, but I'm here for learning ;)

                • 5. Re: Problem with 1-Many Relationships
                  tdang

                  Hi Daniel,

                  No new collection will be created by called the abstract get method for cmr-field. This abstract get method, in this case getProductBeans, will return a collection containing products of a corresponding category. All changes (removing or addning etc.) in this collection will reflect to the Category bean and will be persistence by the container.

                  It is the same as common objects, if you do not clone that object and change its state, changes will be save in the state of that object.

                  I am sure that not thing wrong with my implementation, but I really do not know where the problem is.

                  • 6. Re: Problem with 1-Many Relationships
                    jonmartin

                    I think you have a problem with your transactions. I might be wrong, but, as far as I can see from ejb-jar.xml, all methods has transaction attribute Required. So, if you're not already in a trans when getProductBeans is called, one will be created for you. But, it'll terminate when getProductBeans terminate, and hence the add-call on the collection returned will occur outside the trans. By specifying that getProductBeans has Mandatory transaction attribute the problem will be more visible. If your addProducts(...) method occurs in a session facade, just make sure it has the Required attribute (and that getProductBeans doesn't have RequiresNew which would always fail).

                    Alternatively you could rewrite to something like this:

                    // the following three lines replace this one:
                    // c.getProductBeans().add(p);

                    Collection prodBeans = new ArrayList(c.getProductBeans());
                    prodBeans.add(p);
                    c.setProductBeans(prodBeans);

                    That wouldn't scale well, so I won't recommend it.

                    • 7. Re: Problem with 1-Many Relationships
                      tdang

                      Hi jonmartin,

                      first thanks for studying the attached files.

                      The addProducts(...) method is in a session facade called ClientServices, and I added the following section in ejb-jar.xml:


                      <ejb-name>ClientServices</ejb-name>
                      <method-name>*</method-name>


                      But it does not still work.

                      As I mentioned, I have another project that still works fine. I just copy the configuration files and modifiy them.


                      • 8. Re: Problem with 1-Many Relationships
                        jonmartin

                        I can't really understand how the container can complain about the .add-method not running in the same transaction. Please post it if you find the answer.

                        • 9. Re: Problem with 1-Many Relationships
                          tdang

                          It is my mistake. After changing <transaction-type>Bean</transaction-type> to
                          <transaction-type>Container</transaction-type>, it works fine.

                          Thanks a lot for your help.