4 Replies Latest reply on Jun 15, 2005 12:12 PM by rpa_rio

    DeploymentException: Mappings were not provided

    redbeard15

      I'm running:
      - JBoss 3.2.3
      - Xdoclet 1.2.1
      - MySQL 4.0.21
      - Linux RedHat 9

      I have what seems to be a rather classic data model:

      Items:
      - itemId
      - price
      - cost
      - size
      - productId

      Products:
      - productId
      - name
      - desc
      - categoryId

      Category:
      - categoryId
      - name
      - desc

      A category consists of a number of products, a product consists of a number of (individual) items. I also need composite keys on the DB tables (to guard against rows containing the same ID value). For 'Item' table, composite key is 'itemId-productId', for 'Products' table, key is 'productId-categoryId'.

      I have CMP beans for each and I can get the relationship set (and working!) between Items and Products (But products with only 'productId' as PK).

      It seems that I have to specify a CMP field (in my ItemBean) for the 'productId' in order to get the 'ItemPK' class generated with a composity key.

      My (abbrieviated) Xdoclet tags for ItemBean look like:

      /** Class tag
      * @ejb.bean name="Item" type="CMP" view-type="local"
      * schema="Item" cmp-version="2.x"
      */
      public abstract class ItemBean implements EntityBean {
      /**
      * @ejb.pk-field
      * @ejb.persistence column-name="itemId"
      * @ejb.interface-method
      * @ejb.transaction type="Supports"
      */
      public abstract String getItemId( );
      public abstract void setItemId( String ItemId );

      /**
      * @ejb.pk-field
      * @ejb.persistence column-name="productId"
      * @ejb.interface-method
      * @ejb.transaction type="Supports"
      */
      public abstract String getProductId( );
      public abstract void setProductId( String ProductId );

      /**
      * @ejb.interface-method
      * @ejb.relation name="product-items"
      * role-name="item-belongs_to-product"
      * cascade-delete="yes"
      *
      * @jboss.relation
      * fk-column="productId"
      * related-pk-field="productId"
      * fk-contraint="true"
      *
      */
      public abstract ProductLocal getProduct( );
      public abstract void setProduct( ProductLocal product );
      .
      }

      My ProductBean class looks similar (with field names changed, of course). If I just specify a single '@ejb.pk-field' (on productId) in the ProductBean, I can get the Item/Product stuff work just fine. However, when I add the 'categoryId' CMP field (e.g., add another '@ejb.pk-field' for the 'categoryId') the deployment fails. It seems I need to add this 'ejb.pk-field' in the ProductBean to get a composite key generated in the ProductPK class (productId-categoryId composite key).

      Here's what JBoss says when I try to deploy this set of beans:

      2004-10-21 15:06:07,142 INFO [org.jboss.ejb.EjbModule] Deploying Item
      2004-10-21 15:06:07,177 INFO [org.jboss.ejb.EjbModule] Deploying Product
      2004-10-21 15:06:08,023 ERROR [org.jboss.ejb.EntityContainer] Starting failed
      org.jboss.deployment.DeploymentException: Mappings were not provided for all fields: unmaped fields=[categoryId] in role=product-has-items

      Wha? Why would the 'product-has-items' relationship care about the 'categoryId' field? Is there a simple solution?

      Thanks,
      R

        • 1. Re: DeploymentException: Mappings were not provided
          redbeard15

          I think I figured out the problem. The problem solution is not along the lines of how to get Xdoclet to tell JBoss what to do, but rather change my approach to the problem. Quite frankly, I've only been working with EJBs for a month, so I'm not even a 'newbie'.....

          Bear with me on this one....... I have spent many years developing applications where I design a data model and then an (application) object model, complete with DB I/O code to manipulate the data model. This type of approach allows one to create an object model and code to fill it from a rather arcane data model, as long as one writes the DB I/O code.

          However, I was tired of writing DB I/O code and wanted someone else to do it, hence my desire to use CMP-based EJBs. Soooo, I went about designing my data model, complete with composite keys, etc. and tried to coax JBoss (using CMP EJBs) to manipulate it.

          <side-thought>
          Quite frankly, designing an application server model (like CMP-based EJBs) to do DB I/O for someone else would seem like a daunting task. Adding composite keys to that mix almost seems incomprehensible..... I wouldn't know where to begin to design a system (or a specificiation that someone else could write a system on) to do this..... But if someone wrote this application server, I'll use it!
          </side-thought>

          I found it possible to create CMP-based EJBs with composite keys at one level of my product hierarchy. However, I was having trouble with composite keys at multiple levels. I was trying to force JBoss into submission (e.g., 'do what I want!!!'). However, that's when I realized the error of my approach (at about 2 AM).

          I'm going to change my approach (maybe in a couple of days, I need to step away from this problem for a day... :| ) to the following: design the object model and CMP-based EJBs on that model. Then, design a data model that fits the data I have from my client. This means tweaking the data model schema structure. Fortunately, this is a new application so I'm at liberty to do this.

          I know this approach will not appease those who are trying to use CMP-based EJBs on an existing and probably complex data model. Unfortunately, you may have to write BMP EJBs for some of those solutions. But like I said, I'm not even a newbie at EJBs so take my advice with a grain of 'NaCl'.

          Any other thoughts?

          I'm going back to bed.....

          • 2. Re: DeploymentException: Mappings were not provided

             

            "rjl@mm.com" wrote:
            I'm running:
            - JBoss 3.2.3
            - Xdoclet 1.2.1
            - MySQL 4.0.21
            - Linux RedHat 9

            I have what seems to be a rather classic data model:

            Items:
            - itemId
            - price
            - cost
            - size
            - productId

            Products:
            - productId
            - name
            - desc
            - categoryId

            Category:
            - categoryId
            - name
            - desc

            A category consists of a number of products, a product consists of a number of (individual) items. I also need composite keys on the DB tables (to guard against rows containing the same ID value). For 'Item' table, composite key is 'itemId-productId', for 'Products' table, key is 'productId-categoryId'.

            I have CMP beans for each and I can get the relationship set (and working!) between Items and Products (But products with only 'productId' as PK).

            It seems that I have to specify a CMP field (in my ItemBean) for the 'productId' in order to get the 'ItemPK' class generated with a composity key.

            My (abbrieviated) Xdoclet tags for ItemBean look like:

            /** Class tag
            * @ejb.bean name="Item" type="CMP" view-type="local"
            * schema="Item" cmp-version="2.x"
            */
            public abstract class ItemBean implements EntityBean {
            /**
            * @ejb.pk-field
            * @ejb.persistence column-name="itemId"
            * @ejb.interface-method
            * @ejb.transaction type="Supports"
            */
            public abstract String getItemId( );
            public abstract void setItemId( String ItemId );

            /**
            * @ejb.pk-field
            * @ejb.persistence column-name="productId"
            * @ejb.interface-method
            * @ejb.transaction type="Supports"
            */
            public abstract String getProductId( );
            public abstract void setProductId( String ProductId );

            /**
            * @ejb.interface-method
            * @ejb.relation name="product-items"
            * role-name="item-belongs_to-product"
            * cascade-delete="yes"
            *
            * @jboss.relation
            * fk-column="productId"
            * related-pk-field="productId"
            * fk-contraint="true"
            *
            */
            public abstract ProductLocal getProduct( );
            public abstract void setProduct( ProductLocal product );
            .
            }

            My ProductBean class looks similar (with field names changed, of course). If I just specify a single '@ejb.pk-field' (on productId) in the ProductBean, I can get the Item/Product stuff work just fine. However, when I add the 'categoryId' CMP field (e.g., add another '@ejb.pk-field' for the 'categoryId') the deployment fails. It seems I need to add this 'ejb.pk-field' in the ProductBean to get a composite key generated in the ProductPK class (productId-categoryId composite key).

            Here's what JBoss says when I try to deploy this set of beans:

            2004-10-21 15:06:07,142 INFO [org.jboss.ejb.EjbModule] Deploying Item
            2004-10-21 15:06:07,177 INFO [org.jboss.ejb.EjbModule] Deploying Product
            2004-10-21 15:06:08,023 ERROR [org.jboss.ejb.EntityContainer] Starting failed
            org.jboss.deployment.DeploymentException: Mappings were not provided for all fields: unmaped fields=[categoryId] in role=product-has-items

            Wha? Why would the 'product-has-items' relationship care about the 'categoryId' field? Is there a simple solution?

            Thanks,
            R


            Have you found the solution?

            • 3. Re: DeploymentException: Mappings were not provided
              redbeard15

              Yes, I did find a solution. The details:

              1) For the data model, I specify a single (auto_increment) field for primary key and single field for a 'parent' key. Then I create a 'unique index' on the logical key (e.g., productID) and parentKey. My 'product' table follows:

              create table if not exists store_product (
               productKey integer not null auto_increment,
               parentKey integer,
               productId varchar (40),
               name varchar (80),
               description varchar (255),
               INDEX productKey_indx (productKey),
               INDEX productID_indx (productId),
               INDEX parentKey_indx (parentKey),
               UNIQUE INDEX (parentKey, productId),
               PRIMARY KEY (productKey)
              ) type=InnoDB;
              

              All other tables in this hierarchy follow the same pattern.

              In the ProductBean, I specify a single field as a primary key:
               /**
               * @ejb.pk-field
               * @ejb.persistence
               * column-name="productKey"
               * @ejb.interface-method
               * @ejb.transaction
               * type="Supports"
               * @jboss.persistence
               * auto-increment="true"
               */
               public abstract java.lang.Integer getProductKey ();
              
               public abstract void setProductKey (java.lang.Integer ProductKey);
              

              2) In the ProductBean, I have a finder method defined to find an entry with the appropriate logical key structure:
               * @ejb.finder
               * signature="ProductLocal findById (java.lang.String iId, java.lang.Integer pKey)"
               * query="SELECT OBJECT(a) FROM Product AS a WHERE (a.productId = ?1) AND (a.typeCategory1.typeCatKey = ?2)"
               * view-type="local"
              

              3) For the relationship with the parent, I specify a single field key, as follows:
               /**
               * @ejb.interface-method
               * @ejb.relation
               * name="typeCategory1-products"
               * role-name="product-belongs_to-typeCategory1"
               * cascade-delete="yes"
               *
               * @jboss.relation
               * fk-column="parentKey"
               * related-pk-field="typeCatKey"
               * fk-contraint="true"
               */
               public abstract TypeCategory1Local getTypeCategory1 ();
              
               public abstract void setTypeCategory1 (TypeCategory1Local typeCategory1);
              

              4) in the parent bean (TypeCategory1), I have an 'addChild(ProductValue)' business method that adds a Product entry. The following code is a summary of the real code, error checking, etc., removed:
               /**
               * @ejb.interface-method
               * Add a child (product entry).
               */
              
               public Integer addChild (ProductValue child)
               throws FinderException, CreateException, DuplicateException
               {
               Integer objKey = null;
               ProductLocal oLocal;
               ProductLocalHome oHome = ProductUtil.getLocalHome();
               boolean dupfound = true;
               try {
               olocal = oHome.findById(child.getProductId(), getTypeCatKey());
               } catch (ObjectNotFoundException OE) {
               dupFound = false;
               }
               if (! dupFound) {
               oLocal = oHome.create (child);
               getProducts().add (oLocal);
               objKey = oLocal.getProductKey();
               return objKey;
               } else {
               throw new DuplicateException();
               }
               }
              

              The rest of the beans in the hierarchy follow this same pattern.

              The key to the design here is to separate the logical vs. physical key structures. I use a single field as physical (and bean) primary key, however, this pattern allows for any number of fields to be used as a logical key. I just happen to use a single field in this example. This pattern seems to work well, but may be a bit slow in adding records....

              You can do more tweaking, like adding Value objects for the many side of a relationship to quickly access children (but be very careful here, you don't want to read your entire catalog into memory!!), or use the JBoss.relation-read-ahead xdoclet tag to tell the container to read the entire child object in one SQL statement, etc.

              Hope this helps.

              • 4. Re: DeploymentException: Mappings were not provided

                A lot! Thanks!