12 Replies Latest reply on Apr 15, 2005 1:08 AM by fmfaulkner

    CMR relation on NOT NULL foreign keys

      Hi everybody!

      Does anybody know how to set up a one to one cmr relationship build upon a foreign key constraint that owns a NOT NULL constraint?

      Setting:
      I implemented two CMP beans EntityA and EntityB corresponding to tables A and B. Table A refers to table B's primary key via a foreign key constraint. This foreign key is further restricted by a NOT NULL constraint.
      Since the CMR relation on the foreign key has to be set in ejbPostCreate() but the database insert takes place between the ejbCreate() and ejbPostCreste() methods, it fails due to a voilated NOT NULL constraint.
      I tried to defer the insert using a custom container configuration merged into jboss.xml:
      ...

      <ejb-name>EntityA</ejb-name>
      <jndi-name>EntityAHome</jndi-name>
      <local-jndi-name>EntityArLocalHome</local-jndi-name>
      <configuration-name>INSERT after ejbPostCreate Container</configuration-name>
      <ejb-ref>
      <ejb-ref-name>ejb/EntityB</ejb-ref-name>
      <jndi-name>EntityBHome</jndi-name>
      </ejb-ref>
      <method-attributes>
      </method-attributes>

      ...
      <container-configurations>
      <container-configuration extends="Standard CMP 2.x EntityBean">
      <container-name>INSERT after ejbPostCreate Container</container-name>
      <insert-after-ejb-post-create>true</insert-after-ejb-post-create>
      </container-configuration>
      </container-configurations>


      Unfortunately this does not work and and yields to the the following error
      [java] Data contains multiple values, but this cmr field is single valued; nested exception is:
      [java] javax.ejb.EJBException: Data contains multiple values, but this cmr field is single valued; - nested throwable: (javax.ejb.EJBException: Data contains multiple values, but this cmr field is single valued)
      [java] at org.jboss.ejb.plugins.LogInterceptor.handleException(LogInterceptor.java:262)
      [java] at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:195)
      [java] at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
      [java] at org.jboss.ejb.StatelessSessionContainer.internalInvoke(StatelessSessionContainer.java:331)
      [java] at org.jboss.ejb.Container.invoke(Container.java:700)


      Thanks
      Stefan

        • 1. DATE/TIME problem with Oracle: org.jboss.tm.JBossRollbackExc

          Hi All,

          I have a problem with one field of sql-type DATE in Oracle9i. I have e CMP bean related to this data defined so (using XDoclet1.2):

          /**
           * Returns the lastUpdate
           * @return the lastUpdate
           *
           * @ejb.persistent-field
           * @ejb.persistence
           * column-name="LASTUPDATE"
           * sql-type="DATE"
           *
           * @ejb.interface-method
           */
           public abstract java.sql.Timestamp getLastUpdate();

          It this field I have data like this: "08.03.2002 09:12:43"
          I have no error at deploy but at test I've got this error onmly for this field:

          15:16:25,008 ERROR [LogInterceptor] TransactionRolledbackLocalException in method: public abstract java.sql.Timestamp de
          .prisma.gillette.ejb.peps.AbteilungLocal.getLastUpdate(), causedBy:
          org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl [FormatId=257, GlobalId=pc03//1231, Br
          anchQual=] status=STATUS_NO_TRANSACTION; - nested throwable: (javax.ejb.EJBException: Store failed; CausedByException is
          :
          ORA-01031: Unzureichende Berechtigungen
          )
          at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:413)
          at org.jboss.ejb.plugins.TxInterceptorCMT.endTransaction(TxInterceptorCMT.java:398)
          at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:277)
          at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:128)
          at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:118)
          at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:191)
          at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderInterceptor.java:122)
          at org.jboss.ejb.EntityContainer.internalInvoke(EntityContainer.java:489)
          at org.jboss.ejb.Container.invoke(Container.java:700)
          at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invoke(BaseLocalProxyFactory.java:375)
          at org.jboss.ejb.plugins.local.EntityProxy.invoke(EntityProxy.java:38)
          at $Proxy55.getLastUpdate(Unknown Source)
          at org.apache.jsp.ejbtest_jsp._jspService(ejbtest_jsp.java:231)
          at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:137)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
          at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:210)
          at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:295)
          at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:241)
          at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:247)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:193)
          at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:256)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
          at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
          at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
          at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
          at org.jboss.web.tomcat.security.JBossSecurityMgrRealm.invoke(JBossSecurityMgrRealm.java:220)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
          at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
          at org.apache.catalina.valves.CertificatesValve.invoke(CertificatesValve.java:246)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
          at org.jboss.web.tomcat.tc4.statistics.ContainerStatsValve.invoke(ContainerStatsValve.java:76)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
          at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
          at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
          at org.apache.catalina.core.StandardContext.invoke(StandardContext.java:2417)
          at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:180)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
          at org.apache.catalina.valves.ErrorDispatcherValve.invoke(ErrorDispatcherValve.java:171)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
          at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:172)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
          at org.jboss.web.tomcat.security.SecurityAssociationValve.invoke(SecurityAssociationValve.java:65)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
          at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:577)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:641)
          at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
          at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
          at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:174)
          at org.apache.catalina.core.StandardPipeline$StandardPipelineValveContext.invokeNext(StandardPipeline.java:643)
          at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:480)
          at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:995)
          at org.apache.coyote.tomcat4.CoyoteAdapter.service(CoyoteAdapter.java:197)
          at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:781)
          at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:549)
          at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:605)
          at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:677)
          at java.lang.Thread.run(Thread.java:534)
          Caused by: javax.ejb.EJBException: Store failed; CausedByException is:
          ORA-01031: Unzureichende Berechtigungen

          at org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreEntityCommand.execute(JDBCStoreEntityCommand.java:144)
          at org.jboss.ejb.plugins.cmp.jdbc.JDBCStoreManager.storeEntity(JDBCStoreManager.java:627)
          at org.jboss.ejb.plugins.CMPPersistenceManager.storeEntity(CMPPersistenceManager.java:421)
          at org.jboss.resource.connectionmanager.CachedConnectionInterceptor.storeEntity(CachedConnectionInterceptor.java
          :387)
          at org.jboss.ejb.EntityContainer.storeEntity(EntityContainer.java:714)
          at org.jboss.ejb.GlobalTxEntityMap.synchronizeEntities(GlobalTxEntityMap.java:149)
          at org.jboss.ejb.GlobalTxEntityMap$GlobalTxEntityMapSynchronize.beforeCompletion(GlobalTxEntityMap.java:215)
          at org.jboss.tm.TransactionImpl.doBeforeCompletion(TransactionImpl.java:1308)
          at org.jboss.tm.TransactionImpl.commit(TransactionImpl.java:347)
          ... 59 more
          15:16:25,388 ERROR [STDERR] org.jboss.tm.JBossTransactionRolledbackLocalException: null; CausedByException is:
          Unable to commit, tx=TransactionImpl:XidImpl [FormatId=257, GlobalId=pc03//1231, BranchQual=] status=STATUS_NO_T
          RANSACTION; - nested throwable: (javax.ejb.EJBException: Store failed; CausedByException is:
          ORA-01031: Unzureichende Berechtigungen
          ); - nested throwable: (org.jboss.tm.JBossRollbackException: Unable to commit, tx=TransactionImpl:XidImpl [FormatId=257,
          GlobalId=pc03//1231, BranchQual=] status=STATUS_NO_TRANSACTION; - nested throwable: (javax.ejb.EJBException: Store fail
          ed; CausedByException is:
          ORA-01031: Unzureichende Berechtigungen
          ))
          15:16:25,418 ERROR [STDERR] at org.jboss.ejb.plugins.TxInterceptorCMT.throwJBossException(TxInterceptorCMT.java:485)

          15:16:25,428 ERROR [STDERR] at org.jboss.ejb.plugins.TxInterceptorCMT.endTransaction(TxInterceptorCMT.java:403)
          15:16:25,428 ERROR [STDERR] at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:277)

          15:16:25,438 ERROR [STDERR] at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:128)
          15:16:25,438 ERROR [STDERR] at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:118)
          15:16:25,448 ERROR [STDERR] at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:191)
          15:16:25,448 ERROR [STDERR] at org.jboss.ejb.plugins.ProxyFactoryFinderInterceptor.invoke(ProxyFactoryFinderIntercep
          tor.java:122)
          15:16:25,458 ERROR [STDERR] at org.jboss.ejb.EntityContainer.internalInvoke(EntityContainer.java:489)
          15:16:25,458 ERROR [STDERR] at org.jboss.ejb.Container.invoke(Container.java:700)
          15:16:25,458 ERROR [STDERR] at org.jboss.ejb.plugins.local.BaseLocalProxyFactory.invoke(BaseLocalProxyFactory.java:3
          75)
          15:16:25,468 ERROR [STDERR] at org.jboss.ejb.plugins.local.EntityProxy.invoke(EntityProxy.java:38)
          15:16:25,468 ERROR [STDERR] at $Proxy55.getLastUpdate(Unknown Source)
          15:16:25,478 ERROR [STDERR] at org.apache.jsp.ejbtest_jsp._jspService(ejbtest_jsp.java:231)


          In the same situation with other bean but with date like this: "12.12.2003"
          (without the time) it work's great. I've tried also java.sql.Date and java.sql.Time ... the same output. Another differences is that in the bean that is not working I'm using database Table View. In the case that is working is normal database table. But I think this should be not a problem. I'm using classes12.zip from Oracle9i. I also wonder why at all appears this transaction error at a get method.
          I can't find any reason for this error.

          I'll be thankful to anybody who can give me some hint about this problem.

          Thanks in advance,

          Best Regards,
          Todor

          • 2. Re: CMR relation on NOT NULL foreign keys
            sick1

            Hi,

            Try @jboss.container-configuration name="INSERT after ejbPostCreate Container" if you are using XDoclet. If not, that should be enough to search on. It puts a linke like:

            <configuration-name>INSERT after ejbPostCreate Container</configuration-name>

            under your element for the bean in which you'd like that behavior.

            Mike Sick

            • 3. Re: CMR relation on NOT NULL foreign keys

              Hi!

              That's exactly what I tried. Yes, I am using xdoclet and added
              @jboss.container-configuration name="INSERT after ejbPostCreate Container"
              as a class-level tag but it does not work.

              Maybe I got the wrong container configuration. I put a file "jboss-container.xml" into my xdoclet.mergedir containing the following code:

              <container-configurations>
              <container-configuration extends="Standard CMP 2.x EntityBean">
              <container-name>INSERT after ejbPostCreate Container</container-name>
              <insert-after-ejb-post-create>true</insert-after-ejb-post-create>
              </container-configuration>
              </container-configurations>

              The merge into jboss.xml succeeds but I still get the error “Data contains multiple values, but this cmr field is single valued; ...“

              I found a workaround in setting the foreign key in ejbCreate() so that it is NOT NULL and again the relation in ejbPostCreate(). Additionally, I've had to add a @target-multuple=”yes” to the relation in question which yields a “many” in ejb-jar.xml. It works but unclean though. Multiplicity is one not many and I'm still looking for a semantically correct solution.

              Stefan

              • 4. Re: CMR relation on NOT NULL foreign keys
                jimbrady

                Hi Stefan,
                I am also trying to have not null foreign keys. They work OK if part of the foreign key but I have tried but failed to get insert after ejbPostCreate to work. I haven't looked too hard at it (I changed the database) but would like eventually to find a solution. Have you found what the problem is?
                Jim Brady

                • 5. Re: CMR relation on NOT NULL foreign keys
                  sesques

                  Hi all,

                  I had the same problem myself, and the only workaround I found is the same as you SHA (declare a simple CMP field for the primary key column, setting it in ejbCreate, and setting the CMR field in ejbPostCreate).

                  To understand all this, I think that we must refer to the EJB spec.
                  The EJB spec says that the bean instance must have its primary key available in ejbPostCreate (where you can call getPrimaryKey).
                  JBoss conforms exactly to this point. But it is a problem when the key is generated by the database and some foreign keys cannot be null.

                  The <insert-after-ejb-post-create> set to true is useless in our case, because if you want to do anything in ejbPostCreate, you have an error saying that the primay key is null (or somthing like that). I think it works only when the container generates the key.

                  What a shame, and there is many topics on the subject in this forum, but I never find a response from JBoss. I was Weblogic before, and this problem had been the worse to migrate (Weblogic has the same option insert-after-ejb-post-create but it works !)

                  • 6. Re: CMR relation on NOT NULL foreign keys
                    jimbrady

                    I've moved on to JBOSS 3.2.3 and now it is working (mostly!). However, I am sometimes getting wierd occasional errors that I guess are occuring as follows:
                    Session Bean creates entity A and then related entity B in one transaction. Because entity A is only created at post-ejb-create the creation processes are running in PARALLEL. entity B bombs out because entity A does not yet exist! Happens as I said only sometimes!
                    Is this a known bug? Has anybody else had a similar experience?

                    • 7. Re: CMR relation on NOT NULL foreign keys
                      aloubyansky

                      Show the code and stacktrace.

                      • 8. Re: CMR relation on NOT NULL foreign keys

                        insert-after-ejb-post-create will not work if you use container generated primary keys (like autoincrement) because orimary key must be known before you set the relationship.

                        And youwill have problems during cascade deletes anyway because when the bean is about to be removed it will get cmr fields cleared first and if they are "NOT NULL" then you will have exception with foreign key violation...

                        Frankly speaking the only solution I see so far is just not to use NOT NULL but do a check of CMR field against null in ejbCreate method and throw an exception if it is...

                        If someone knows beter solution, please post here...

                        • 9. Re: CMR relation on NOT NULL foreign keys
                          aloubyansky

                          To workaround cascade-delete problem use http://www.jboss.org/wiki/Wiki.jsp?page=BatchCascadeDelete

                          • 10. Re: CMR relation on NOT NULL foreign keys
                            aloubyansky

                            What was the SQL statement? How are relationships configured and mapped?

                            • 11. Re: CMR relation on NOT NULL foreign keys

                               

                              "loubyansky" wrote:
                              What was the SQL statement? How are relationships configured and mapped?


                              I did not use SQL for that (those are CMP beans). And this happens when I remove a bean which should result in cascade deletes (this works if I remove NOT NULL constrainst from CMR fields and batch cascade deletes).

                              The configuration is the following:

                              Bean A is a 1-side of unidirectional relationship and knows nothing about bean B.

                              Bean B is a Many-side of the relationship and has the following methods:

                              public abstract ALocal getA();
                              public abstract void setA(ALocal newA);

                              public abstract java.lang.Integer getAId();
                              public abstract void setAId(java.lang.Integer aId);

                              where first pair of methods is CMR field and second one is CMP filed mapping to the same column (in order to avoid NOT NULL problem and have autoincrement pk feature working during bean instance creation).


                              ejb-jar.xml:

                              <ejb-relation >
                              <ejb-relation-name>A-B</ejb-relation-name>

                              <ejb-relationship-role >
                              <ejb-relationship-role-name>B belongs to A</ejb-relationship-role-name>
                              Many
                              <cascade-delete/>
                              <relationship-role-source >
                              <ejb-name>B</ejb-name>
                              </relationship-role-source>
                              <cmr-field >
                              <cmr-field-name>a</cmr-field-name>
                              </cmr-field>
                              </ejb-relationship-role>

                              <ejb-relationship-role >
                              <ejb-relationship-role-name>A has B</ejb-relationship-role-name>
                              One
                              <relationship-role-source >
                              <ejb-name>A</ejb-name>
                              </relationship-role-source>
                              </ejb-relationship-role>

                              </ejb-relation>

                              jbosscmp-jdbc.xml:
                              <ejb-relation>
                              <ejb-relation-name>A-B</ejb-relation-name>

                              <ejb-relationship-role>
                              <ejb-relationship-role-name>B belongs to A</ejb-relationship-role-name>
                              <fk-constraint>true</fk-constraint>
                              <key-fields/>
                              <batch-cascade-delete/>

                              </ejb-relationship-role>
                              <ejb-relationship-role>
                              <ejb-relationship-role-name>A has B</ejb-relationship-role-name>
                              <key-fields>
                              <key-field>
                              <field-name>id</field-name>
                              <column-name>nationid</column-name>
                              </key-field>
                              </key-fields>

                              </ejb-relationship-role>
                              </ejb-relation>

                              • 12. Re: CMR relation on NOT NULL foreign keys
                                fmfaulkner

                                insert-after-ejb-post-create works in Weblogic with Oracle sequences with non-null FK fields being set in ejbPostCreate.

                                I wish someone could provide a definitive answer on how to accomplish this for JBoss 4.0 and MySql.