9 Replies Latest reply on Jun 6, 2003 11:42 AM by alanx1

    CMR foreign key dependencies on ejbCreate() ?

    sysuser1

      What is the approach used in JBoss CMP with regards to handling foreign key dependencies of related entities on ejbCreate ?

      Supposing a "Customer" entity with a CMR for "Address" entity. From a DB perspective CUSTOMER table has an ADDRESS_ID foreign key to ADDRESS table which is NOT NULL. When I create a Customer, I get Could not create entity:java.sql.SQLException: ORA-01400: cannot insert NULL into ("ABC"."CUSTOMER"."ADDRESS_ID") because the address has not been created yet.

      In WebLogic, the way the application I'm migrating does this is by using the entity deployment tags ...

      <delay-database-insert-until>ejbPostCreate</delay-database-insert-until>

      and specifies this in the Entity bean as follows ...

      public Object ejbCreate(Customer customer)
      throws NamingException, CreateException
      {
      setFirstName(customer.getFirstName());
      setMiddleName(customer.getMiddleName());
      setLastName(customer.getLastName());
      setDateOfBirth(getDate(customer.getDateOfBirth()));
      setGender(customer.getGender());
      setSsn(customer.getSsn());
      setPhone(customer.getPhone());
      return null;
      }

      public void ejbPostCreate(Customer customer)
      throws NamingException, CreateException {
      try {
      setAddress(addrHome.create(customer.getAddress()));
      } catch (CreateException e) {
      throw e;
      }
      }

      Does JBoss have anything equivalent or is there an approach that someone can recommend ?

      thanks,
      Trev,

        • 1. Re: CMR foreign key dependencies on ejbCreate() ?
          tommyg

          With the 3.2 release, one way to get around this problem is to define the foreign key fields. So for the 'many' object', you define the foreing key field and when you call ejbcreate , you set it. This will avoid your NOT NULL problem.

          • 2. Re: CMR foreign key dependencies on ejbCreate() ?
            sysuser1

            Thanks for the reply, I added <fk-constraint>true</fk-constraint> to <ejb-relationship-role> as you said but still got problems ... is this what you mean by defining foreign key fields? am I missing something else ? Thanks again!
            Trev

            <ejb-relation>
            <ejb-relation-name>Customer-Address</ejb-relation-name>
            <foreign-key-mapping/>
            <ejb-relationship-role>
            <ejb-relationship-role-name>many-CustomerEJB@address-Have-AddressEJB</ejb-relationship-role-name>
            <fk-constraint>true</fk-constraint>
            <key-fields/>
            </ejb-relationship-role>
            <ejb-relationship-role>
            <ejb-relationship-role-name>one-AddressEJB-Has-CustomerEJB</ejb-relationship-role-name>
            <fk-constraint>true</fk-constraint>
            <key-fields>
            <key-field>
            <field-name>id</field-name>
            <column-name>address_id</column-name>
            </key-field>
            </key-fields>
            </ejb-relationship-role>
            </ejb-relation>
            <ejb-relation>

            • 3. Re: CMR foreign key dependencies on ejbCreate() ?
              tommyg

              No I mean add the field as a normal field using setter and getters, then when you call ejbCreate() set the value of the field.

              So, say you have a 'one' object, and a 'many' object has a field that holds the value to the foreign key (pointing to the one object/table), when you call ejbCreate() in the 'many' object you set the value of the field for the foreign key. This avoids NOT NULL exceptions.

              This has been an issue I have been grappling with for a while. You might want to check other threads in which I asked the same question.

              By the way, Hibernate is a pretty awesome o/r mapper. You might want to look at it. By using Hibernate in a Session bean, JBoss handles threading, transactions, database configuration and pooling, and Hibernate seamlessly maps the objects to the tables.

              • 4. Re: CMR foreign key dependencies on ejbCreate() ?
                sweber42

                I encountered this same problem. I am using middlegen to create the entity beans from an evolving schema, so I was motivated to figure out a workaround that didn't involve custom rewrites. It turns out that the middlegen Data Object constructor is just the ticket.

                Here is my middlegen target







                <cmp20
                destination="${middlegen.dir}"
                package="${pkg}.entity"
                interfacepackage="${pkg}.entity"
                jndiprefix="${project.name}"
                pkclass="false"
                dataobject="true"
                viewtype="local"
                mergedir="${src.dir}/middlegen"
                readonly="false"
                guid="false">

                </cmp20>



                for
                java.naming.factory.initial=org.jnp.interfaces.NamingContextFactory
                java.naming.provider.url=localhost

                (I also have a file in my merge directory called cmp20-ALL-class-comments.txt that contains the line
                * @ejb-transaction type="Required"
                since middlegen seems to have forgotten about the need to specify transaction types.)

                The generated code adheres to the classic EJB pattern for the custom constructors, but uses the pattern described by tommyg for the data object constructor. So by calling the data object version in my session beans, I get to keep the NOT NULL constraint on all my foreign key fields without having to rewrite any of the middlegen-generated source files.

                hope this helps
                --susan

                • 5. Re: CMR foreign key dependencies on ejbCreate() ?
                  sweber42

                  urk, I posted too soon. Turns out that the xDoclet generated xCMP.java file edits out relationship fields in setData(). The workaround is to patch xdoclet-ejb-module-1.2b2.jar by changing line 52 of entity-body.xdt from
                  <XDtEjbPersistent:forAllPersistentFields pk="true">

                  to
                  <XDtEjbPersistent:forAllPersistentFields >

                  --susan

                  • 6. Re: CMR foreign key dependencies on ejbCreate() ?
                    tbrower

                    Setting the foreign key field in ejbCreate() instead of ejbPostCreate() works fine in JBoss but not in Weblogic. I need a solution which will work across app servers. I define the foreign key column as both a CMF and CMR field. When setting the foreign key field in ejbCreate(), I use the CMF version. When I want to use the relationship, I use the CMR version. Weblogic does not allow me to use the CMR version in ejbCreate(). Anybody got this working across app servers, without losing the NOT NULL attribute on the foreign key column?

                    • 7. Re: CMR foreign key dependencies on ejbCreate() ?
                      tbrower

                      This seems to work. If the foreign key is also part of the primary key, then weblogic and jboss both allow the CMP-field to be set in ejbCreate(), otherwise the foreign key field must be set in ejbPostCreate() and must allow nulls. So it appears that if you want a foreign key to be NOT NULL, it must be part of the primary key.

                      • 8. Re: CMR foreign key dependencies on ejbCreate() ?
                        rblack

                        tommyg -

                        Using 3.2, I'm unable to set the foreign key in ejbCreate() when using foreign key CMP. The server throws the following error:

                        javax.ejb.EJBException: null; CausedByException is:
                        A CMR field cannot be set in ejbCreate; this should be done in the ejbPostCreate method instead [EJB 2.0 Spec. 10.5.2].

                        It knows you're breaking the spec and doesn't let you do it!

                        The only other solution I've seen to this problem is to delay the not null constraint checking until the transaction is committed. Well not every database can do this. It seems to me that JBoss should delay the initial database insert until after ejbPostCreate has been called. Is this planned? 4.0 maybe?

                        • 9. Re: CMR foreign key dependencies on ejbCreate() ?
                          alanx1

                          There seems a few threads related to this topic (but the forum seach seems very unreliable), this is my understanding of the CMR mapping to CMP solution to this problem.

                          In ejb-jar.xml insert a CMP field in the bean with the foreign key.
                          In jbosscmp-jdbc.xml map the new CMP field to the foreign key database column.
                          In the EJB code insert Abstract get/set methods for the new CMP field. In the ejbCreate populate the CMP field with the related key.
                          (This ensures that when the insert occurs after ejbCreate the foreign key isn't null).
                          Populate the CMR as usual in ejbPostCreate.

                          It's a bit of a bodge, and I agree it would be better to have the option to delay the insert until after ejbPostCreate.