4 Replies Latest reply on Apr 3, 2007 3:15 AM by oskar.carlstedt

    Etity reference problems

    oskar.carlstedt

      Hi All!

      I have a quite strange data model, but it has it explanation. Lets say we have the following tables in my db:

      
      -----------
      | A |
      -----------
      | Aid (pk)|
      | |
      -----------
      
      
      -----------
      | B |
      -----------
      | Bid (pk)|
      | Aid (fk)|
      | |
      -----------
      
      
      -----------
      | C |
      -----------
      | Aid (pk)|
      | Bid (fk)|
      | |
      -----------
      There is a unique constraint on the tuple (Aid, Bid)
      
      


      A textual explanation of the model:
      A is the master table. It has more info than the columns I described. But the most important one is the primary key Aid.
      B is another table. Items in B references A, i.e. there are many B items on one A item (many-to-one).
      C is a table that will point out one row in B from A. So there is a one-to-one relationship between A and B that is stored in table C.

      The problem here is that we have a kind of circular reference. Is it possible to model this in EJB3 with annotation. I have tried a lot, but nothing works. I often get a NPE for OneToOne on line 135.

      The classesre defined as follows:
      
      public class A {
      
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       @Column(name = "Aid")
       private Integer id;
      
       @OneToMany(cascade = CascadeType.ALL, mappedBy = "A", fetch = FetchType.LAZY)
       private List<B> Bs = new ArrayList<B>();
      
      
       @OneToOne
       @PrimaryKeyJoinColumn
       private C c = null;
      
       ...
      }
      
      
      
      public class B {
      
       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       @Column(name = "Bid")
       private Integer Bid;
      
       @ManyToOne
       @JoinColumn(name = "Aid", nullable = false)
       private A a;
      
       ...
      }
      
      
      public class C {
      
       @Id
       @Column(name = "Aid")
       private Integer id;
      
       @OneToOne
       @JoinColumn(name = "Aid", nullable=false)
       private A a;
      
       @OneToOne
       @PrimaryKeyJoinColumn
       private B b;
      
       ...
      }
      
      


      So, it is a problem doing this way. Does anyone know how to get it to work. I know the datamodel is a bit tricky - the explanation I have is that we want all references to A be in the same direction.

      Environment:
      JBoss 4.0.5.GA
      JBoss EJB3 RC9 Patch
      JBoss WS 1.2.0GA SP1

      Database MySQL 5, no InnoDB

      I would really appreciate if someone can help me
      Best Regards
      Oskar



        • 1. Re: Etity reference problems

           

          I often get a NPE for OneToOne on line 135.


          Can you be a bit more specific?

          Regards

          Felix

          • 2. Re: Etity reference problems
            oskar.carlstedt

            Hi!

            Here is the stack trace.


            ...
            2007-04-02 07:57:58,337 DEBUG [org.hibernate.cfg.Configuration] processing extends queue
            2007-04-02 07:57:58,337 DEBUG [org.hibernate.cfg.Configuration] processing collection mappings
            2007-04-02 07:57:58,337 DEBUG [org.hibernate.cfg.annotations.PropertyBinder] Building property a
            2007-04-02 07:57:58,337 DEBUG [org.hibernate.cfg.annotations.PropertyBinder] Cascading a with all
            2007-04-02 07:57:58,353 DEBUG [org.jboss.ejb3.ServiceDelegateWrapper] Starting failed persistence.units:ear=myservice.ear,jar=myservice.jar,unitName=myservice
            java.lang.NullPointerException
             at org.hibernate.cfg.OneToOneSecondPass.doSecondPass(OneToOneSecondPass.java:135)
             at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1054)
             at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:296)
             at org.hibernate.cfg.Configuration.buildMappings(Configuration.java:1039)
             at org.hibernate.ejb.Ejb3Configuration.buildMappings(Ejb3Configuration.java:1211)
             at org.hibernate.ejb.EventListenerConfigurator.configure(EventListenerConfigurator.java:154)
             at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:847)
             at org.hibernate.ejb.Ejb3Configuration.configure(Ejb3Configuration.java:385)
             at org.hibernate.ejb.HibernatePersistence.createContainerEntityManagerFactory(HibernatePersistence.java:126)
             at org.jboss.ejb3.entity.PersistenceUnitDeployment.start(PersistenceUnitDeployment.java:264)
             at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
             at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.jboss.ejb3.ServiceDelegateWrapper.startService(ServiceDelegateWrapper.java:102)
             at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:289)
             at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:245)
             at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
             at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
             at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
             at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
             at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
             at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:978)
             at $Proxy0.start(Unknown Source)
             at org.jboss.system.ServiceController.start(ServiceController.java:417)
             at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
             at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
             at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
             at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
             at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
             at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
             at $Proxy85.start(Unknown Source)
             at org.jboss.ejb3.JmxKernelAbstraction.install(JmxKernelAbstraction.java:96)
             at org.jboss.ejb3.Ejb3Deployment.startPersistenceUnits(Ejb3Deployment.java:467)
             at org.jboss.ejb3.Ejb3Deployment.start(Ejb3Deployment.java:317)
             at org.jboss.ejb3.Ejb3Module.startService(Ejb3Module.java:91)
             at org.jboss.system.ServiceMBeanSupport.jbossInternalStart(ServiceMBeanSupport.java:289)
             at org.jboss.system.ServiceMBeanSupport.jbossInternalLifecycle(ServiceMBeanSupport.java:245)
             at sun.reflect.GeneratedMethodAccessor2.invoke(Unknown Source)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
             at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
             at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
             at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
             at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
             at org.jboss.system.ServiceController$ServiceProxy.invoke(ServiceController.java:978)
             at $Proxy0.start(Unknown Source)
             at org.jboss.system.ServiceController.start(ServiceController.java:417)
             at sun.reflect.GeneratedMethodAccessor9.invoke(Unknown Source)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
             at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
             at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
             at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
             at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
             at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
             at $Proxy29.start(Unknown Source)
             at org.jboss.ejb3.EJB3Deployer.start(EJB3Deployer.java:449)
             at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
             at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
             at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
             at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
             at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
             at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
             at org.jboss.mx.interceptor.DynamicInterceptor.invoke(DynamicInterceptor.java:97)
             at org.jboss.system.InterceptorServiceMBeanSupport.invokeNext(InterceptorServiceMBeanSupport.java:238)
             at org.jboss.ws.integration.jboss42.DeployerInterceptor.start(DeployerInterceptor.java:93)
             at org.jboss.deployment.SubDeployerInterceptorSupport$XMBeanInterceptor.start(SubDeployerInterceptorSupport.java:188)
             at org.jboss.deployment.SubDeployerInterceptor.invoke(SubDeployerInterceptor.java:95)
             at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
             at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
             at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
             at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
             at $Proxy30.start(Unknown Source)
             at org.jboss.deployment.MainDeployer.start(MainDeployer.java:1025)
             at org.jboss.deployment.MainDeployer.start(MainDeployer.java:1015)
             at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:819)
             at org.jboss.deployment.MainDeployer.deploy(MainDeployer.java:782)
             at sun.reflect.GeneratedMethodAccessor17.invoke(Unknown Source)
             at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
             at java.lang.reflect.Method.invoke(Method.java:585)
             at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
             at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
             at org.jboss.mx.interceptor.AbstractInterceptor.invoke(AbstractInterceptor.java:133)
             at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
             at org.jboss.mx.interceptor.ModelMBeanOperationInterceptor.invoke(ModelMBeanOperationInterceptor.java:142)
             at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
             at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
             at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
             at org.jboss.mx.util.MBeanProxyExt.invoke(MBeanProxyExt.java:210)
             at $Proxy8.deploy(Unknown Source)
             at org.jboss.deployment.scanner.URLDeploymentScanner.deploy(URLDeploymentScanner.java:421)
             at org.jboss.deployment.scanner.URLDeploymentScanner.scan(URLDeploymentScanner.java:610)
             at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.doScan(AbstractDeploymentScanner.java:263)
             at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.loop(AbstractDeploymentScanner.java:274)
             at org.jboss.deployment.scanner.AbstractDeploymentScanner$ScannerThread.run(AbstractDeploymentScanner.java:225)
            
            



            //Oskar

            • 3. Re: Etity reference problems

              Two things:

              public class C {
              
               @Id
               @Column(name = "Aid")
               private Integer id;
              
               @OneToOne
               @JoinColumn(name = "Aid", nullable=false)
               private A a;
              
               @OneToOne
               @PrimaryKeyJoinColumn
               private B b;
              
               ...
              }
              


              - This doesn't look good to me. You are mapping the column "Aid" twice.
              - If the tuple(a,b) is unique use an @EmbeddedId.

              2.) Do you need Class C at all? Simply use a @JoinTable:


              public class A {
              
               @Id
               @GeneratedValue(strategy = GenerationType.IDENTITY)
               @Column(name = "Aid")
               private Integer id;
              
               @OneToMany(cascade = CascadeType.ALL, mappedBy = "A", fetch = FetchType.LAZY)
               private List<B> Bs = new ArrayList<B>();
              
              
               @OneToOne
               @JoinTable(name="C",
               joinColumns=@JoinColumn(name="Aid"),
               inverseJoinColumns=@JoinColumn(name="Bid")
               private B b = null;
              
               ...
              }
              


              This will only work if C has some more properties. (And I have never tried a @OneToOne-Relationship using a JoinTable before. YMMV).

              Regards

              Felix

              • 4. Re: Etity reference problems
                oskar.carlstedt

                Thank you for helping me!

                I found the error I did. In my code where I assigned all objects I missed to add the B item to the list of B:s in A. Doing this resolved my problem. The following steps must be applied:

                1. Create A
                2. Create all B:s and add them to A
                3. Create C by using A and the expected B

                I missed to add the B, that was mapped from A and C, to A. Kind of stupidness from my side. I put my working code here for all of you who are interested in this:

                @Entity
                @Table(name = "A")
                public class A implements Serializable {
                
                 @Id
                 @GeneratedValue(strategy = GenerationType.IDENTITY)
                 @Column(name = "Aid")
                 private Integer id;
                
                 @OneToOne(cascade = CascadeType.ALL, mappedBy = "a", fetch = FetchType.EAGER)
                 private C c;
                
                 @OneToMany(cascade = CascadeType.ALL, mappedBy = "a", fetch = FetchType.EAGER)
                 private List<B> bs = new ArrayList<B>();
                
                 ...
                
                 protected A() {};
                
                 public A(...) {
                 ...
                 }
                
                 public List<B> getBs() {
                 return bs;
                 }
                
                 public void setBs(List<B> bs) {
                 this.bs = bs;
                 }
                
                 public void addB(B b) {
                
                 b.setA(this);
                 this.bs.add(b);
                 }
                
                 public C getC() {
                 return c;
                 }
                
                 public void setC(C c) {
                 c.setA(this);
                 this.c = c;
                 }
                
                 ...
                }
                
                
                
                @Entity
                @Table(name = "B")
                public class B implements Serializable {
                
                 @Id
                 @GeneratedValue(strategy = GenerationType.IDENTITY)
                 @Column(name = "Bid")
                 private Integer id;
                
                 @ManyToOne
                 @JoinColumn(name = "Aid", nullable = false)
                 private A a;
                
                 ...
                
                 protected B() {};
                
                 public B(A a, ...) {
                
                 this.a = a;
                 ...
                 }
                
                 public Integer getId() {
                 return id;
                 }
                
                 public void setId(Integer id) {
                 this.id = id;
                 }
                
                 public A getA() {
                 return a;
                 }
                
                 public void setA(A a) {
                 this.a = a;
                 }
                
                 ...
                }
                
                
                
                @Entity
                @Table(name = "C")
                public class C implements Serializable {
                
                 @Id
                 @GeneratedValue(strategy = GenerationType.IDENTITY)
                 @Column(name = "Cid")
                 private Integer id;
                
                 @OneToOne
                 @JoinColumn(name = "Aid", nullable = false)
                 private A a;
                
                 @OneToOne
                 @JoinColumn(name = "Bid", nullable = false)
                 private B b;
                
                
                 protected C() {};
                
                 public C(A a,
                 B b) {
                
                 this.a = a;
                 this.b = b;
                 }
                
                 public Integer getId() {
                 return id;
                 }
                
                 public void setId(Integer id) {
                 this.id = id;
                 }
                
                 public A getA() {
                 return a;
                 }
                
                 public void setA(A a) {
                 this.a = a;
                 }
                
                 public B getB() {
                 return b;
                 }
                
                 public void setB(B b) {
                 this.b = b;
                 }
                }
                
                




                Finally some points:
                - There is an error in my first post. "... mappedBy="A"..." shall be "... mappedBy="a"...". My mistake in the post.

                - This fix requires the C table to carry its own primary key, a Cid.

                - As you say Felix, it doesn't look good to point out Aid twice. This shall work, but it seems to be a bug in hibernate (see http://forum.hibernate.org/viewtopic.php?t=970823). JBoss 4.0.5.GA is using Hibernate 3.2, it shall be fixed in Hibernate 3.3.0. I haven't tried the join table, I will check it out and se what more it gives to me. It might be a kind of shortcut for my C table mapping.

                Thanks again for quick response.

                Best
                Oskar