1 Reply Latest reply on Jul 16, 2009 10:46 PM by Matthew Purdy

    hbm.xml to javax.persistence annotations problems

    Matthew Purdy Newbie

      i created a simple hibernate example using two classes:
      - User
      - TrainingRequest

      User has a set of trainingRequest (one to many)
      TrainingRequest has a user (many to one)

      everything works fine; so i created a new project and converted the *.hbm.xml to annotations, however, it doesnt create the TrainingRequest table correctly and throws exception when trying to build the table.

      the details are below, however, i believe the problem seems to be the following:
      the TrainingRequest hibernate with the annotations only creates two columns the trainingrequest_id key and the user_id foreign key.

      note: i changed the table names from the first project to the second project to simplify the example - but other than that everything is the same.


      the join table annotation from the two classes

      //from User.java
       @OneToMany(cascade = CascadeType.ALL)
       @JoinTable
       (
       name="TrainingRequest",
       joinColumns = @JoinColumn( name="user_id"),
       inverseJoinColumns = @JoinColumn( name="trainingrequest_id")
       )
       private Set<TrainingRequest> trainingRequests;
      
      
      //from TrainingRequest.java
       @ManyToOne()
       @JoinTable
       (
       name="User",
       joinColumns = @JoinColumn( name="trainingrequest_id"),
       inverseJoinColumns = @JoinColumn( name="user_id")
       )
       private User user;
      




      User.hbm.xml (from the first project that works)
      <?xml version="1.0"?>
      <!DOCTYPE hibernate-mapping PUBLIC
       "-//Hibernate/Hibernate Mapping DTD//EN"
       "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
      
      <hibernate-mapping>
       <class name="com.pyxisengineering.test.hibernate.model.User" table="users">
       <id name="id" column="user_id">
       <generator class="increment" />
       </id>
       <property name="username" column="username" />
       <property name="password" column="password" />
      
       <set name="trainingRequests" inverse="true" cascade="all">
       <key column="user_id" />
       <one-to-many class="com.pyxisengineering.test.hibernate.model.TrainingRequest" />
       </set>
      
       </class>
      
      </hibernate-mapping>
      


      TrainingRequest.hbm.xml (from the first project that works)
      <?xml version="1.0"?>
      <!DOCTYPE hibernate-mapping PUBLIC
       "-//Hibernate/Hibernate Mapping DTD//EN"
       "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
      
      <hibernate-mapping>
       <class name="com.pyxisengineering.test.hibernate.model.TrainingRequest" table="trainingrequests">
       <id name="id" column="trainingrequest_id">
       <generator class="increment" />
       </id>
       <property name="subject" column="subject" />
       <property name="summary" column="summary" />
       <property name="cost" column="cost" />
      
       <many-to-one name="user" class="com.pyxisengineering.test.hibernate.model.User" column="user_id" not-null="true"/>
      
       </class>
      
      </hibernate-mapping>
      


      database hibernate creates in the first project that works
      mysql> desc users;
      +----------+--------------+------+-----+---------+-------+
      | Field | Type | Null | Key | Default | Extra |
      +----------+--------------+------+-----+---------+-------+
      | user_id | bigint(20) | NO | PRI | NULL | |
      | username | varchar(255) | YES | | NULL | |
      | password | varchar(255) | YES | | NULL | |
      +----------+--------------+------+-----+---------+-------+
      3 rows in set (0.00 sec)
      
      mysql> desc trainingrequests;
      +--------------------+--------------+------+-----+---------+-------+
      | Field | Type | Null | Key | Default | Extra |
      +--------------------+--------------+------+-----+---------+-------+
      | trainingrequest_id | bigint(20) | NO | PRI | NULL | |
      | subject | varchar(255) | YES | | NULL | |
      | summary | varchar(255) | YES | | NULL | |
      | cost | double | YES | | NULL | |
      | user_id | bigint(20) | NO | MUL | NULL | |
      +--------------------+--------------+------+-----+---------+-------+
      5 rows in set (0.01 sec)
      



      User.java (from second project with annotations)
      package com.pyxisengineering.test.hibernate.model;
      
      import java.util.HashSet;
      import java.util.Set;
      
      import javax.persistence.CascadeType;
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.Id;
      import javax.persistence.JoinTable;
      import javax.persistence.JoinColumn;
      import javax.persistence.OneToMany;
      import javax.persistence.Table;
      
      
      
      @Entity
      @Table(name = "User")
      public class User
      {
       @Id @GeneratedValue
       @Column(name = "user_id")
       private Long id;
      
       @Column(name = "username")
       private String username;
      
       @Column(name = "password")
       private String password;
      
       @OneToMany(cascade = CascadeType.ALL)
       @JoinTable
       (
       name="TrainingRequest",
       joinColumns = @JoinColumn( name="user_id"),
       inverseJoinColumns = @JoinColumn( name="trainingrequest_id")
       )
       private Set<TrainingRequest> trainingRequests;
      
       public User()
       {
       this.init();
      
       }//end default constructor
      
       private void init()
       {
       this.trainingRequests = new HashSet<TrainingRequest>();
      
       }//end initialization function
      
       public Long getId() { return this.id; }
       public void setId(Long id) { this.id = id; }
      
       public String getUsername() { return this.username; }
       public void setUsername(String username) { this.username = username; }
      
       public String getPassword() { return this.password; }
       public void setPassword(String password) { this.password = password; }
      
       public Set<TrainingRequest> getTrainingRequests()
       {
       return this.trainingRequests;
      
       }//end method getTrainingRequest
      
       public void setTrainingRequests(Set<TrainingRequest> trainingRequests)
       {
       if(trainingRequests != null)
       this.trainingRequests = trainingRequests;
       else
       this.init();
      
       }//end method setTrainingRequest
      
       public boolean deleteTrainingRequest(int pos)
       {
       boolean ret = false;
      
       if(pos >= 0 && pos < this.trainingRequests.size())
       {
       this.trainingRequests.remove(pos);
       ret = true;
      
       }//end if in range - delete
      
       return ret;
      
       }//end method deleteTrainingRequest
      
       public void addTrainingRequest(TrainingRequest trainingRequest)
       {
       trainingRequest.setUser(this);
       this.trainingRequests.add(trainingRequest);
      
       }//end method addTrainingRequest
      
       public String toString()
       {
       StringBuffer ret = new StringBuffer(100);
      
       ret.append(this.id);
       ret.append(", ");
       ret.append(this.username);
       ret.append(", ");
       ret.append(this.password);
      
       for(TrainingRequest trainingRequest: this.trainingRequests)
       ret.append("\n" + trainingRequest.toString());
      
       ret.append(" )");
      
       return ret.toString();
      
       }//end method toString
      
      }//end class User
      


      TrainingRequest (from second project with annotations)
      package com.pyxisengineering.test.hibernate.model;
      
      import javax.persistence.Column;
      import javax.persistence.Entity;
      import javax.persistence.GeneratedValue;
      import javax.persistence.Id;
      import javax.persistence.JoinColumn;
      import javax.persistence.JoinTable;
      import javax.persistence.ManyToOne;
      import javax.persistence.Table;
      
      @Entity
      @Table(name = "TrainingRequest")
      public class TrainingRequest
      {
       @Id @GeneratedValue
       @Column(name = "trainingrequest_id")
       private Long id;
      
       @Column(name = "subject")
       private String subject;
      
       @Column(name = "summary")
       private String summary;
      
       @Column(name = "cost")
       private Double cost;
      
       @ManyToOne()
       @JoinTable
       (
       name="User",
       joinColumns = @JoinColumn( name="trainingrequest_id"),
       inverseJoinColumns = @JoinColumn( name="user_id")
       )
       private User user;
      
       public Long getId() { return this.id; }
       public void setId(Long id) { this.id = id; }
      
       public String getSubject() { return this.subject; }
       public void setSubject(String subject) { this.subject = subject; }
      
       public String getSummary() { return this.summary; }
       public void setSummary(String summary) { this.summary = summary; }
      
       public Double getCost() { return this.cost; }
       public void setCost(Double cost) { this.cost = cost; }
      
       public User getUser() { return this.user; }
       public void setUser(User user) { this.user = user; }
      
       public String toString()
       {
       StringBuffer ret = new StringBuffer(100);
      
       ret.append("( ");
      
       ret.append(this.id);
       ret.append(", ");
       ret.append(this.subject);
       ret.append(", ");
       ret.append(this.summary);
       ret.append(", ");
       ret.append(this.cost);
       ret.append(", ");
      
       if(this.user != null)
       ret.append(this.user.getUsername());
       else
       ret.append("user not set - this should never happen");
      
       ret.append(" )");
      
       return ret.toString();
      
       }//end method toString
      
      }//end class TrainingRequest
      



      exceptions when running the second project
      10:45:09,578 INFO Version:15 - Hibernate Annotations 3.3.1.GA
      10:45:09,590 INFO Environment:514 - Hibernate 3.2.7
      10:45:09,593 INFO Environment:547 - hibernate.properties not found
      10:45:09,595 INFO Environment:681 - Bytecode provider name : cglib
      10:45:09,600 INFO Environment:598 - using JDK 1.4 java.sql.Timestamp handling
      10:45:09,669 INFO Configuration:1445 - configuring from resource: /hibernate.cfg.xml
      10:45:09,669 INFO Configuration:1422 - Configuration resource: /hibernate.cfg.xml
      10:45:09,761 INFO Configuration:1560 - Configured SessionFactory: null
      10:45:09,820 INFO AnnotationBinder:418 - Binding entity from annotated class: com.pyxisengineering.test.hibernate.model.User
      10:45:09,851 INFO EntityBinder:424 - Bind entity com.pyxisengineering.test.hibernate.model.User on table User
      10:45:09,928 INFO AnnotationBinder:418 - Binding entity from annotated class: com.pyxisengineering.test.hibernate.model.TrainingRequest
      10:45:09,928 INFO EntityBinder:424 - Bind entity com.pyxisengineering.test.hibernate.model.TrainingRequest on table TrainingRequest
      10:45:09,933 INFO EntityBinder:635 - Adding secondary table to entity com.pyxisengineering.test.hibernate.model.TrainingRequest -> User
      Exception in thread "main" org.hibernate.MappingException: Foreign key (FKEA317035A6FF12E4:TrainingRequest [trainingrequest_id])) must have same number of columns as the referenced primary key (TrainingRequest [user_id,trainingrequest_id])
       at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:90)
       at org.hibernate.mapping.ForeignKey.alignColumns(ForeignKey.java:73)
       at org.hibernate.cfg.Configuration.secondPassCompileForeignKeys(Configuration.java:1282)
       at org.hibernate.cfg.Configuration.secondPassCompile(Configuration.java:1189)
       at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:324)
       at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1305)
       at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:859)
       at com.pyxisengineering.test.hibernate.App.main(App.java:20)
      
      


        • 1. Re: hbm.xml to javax.persistence annotations problems
          Matthew Purdy Newbie

          i figured it out. the problem it was my first time with JPA annotations, now it is clear.

          i used JoinTable annotation, which is used in a many to many relationship, which cause hibernate to create a link table.

          once i switch it back to JoinColumn, it worked the same:

          code from User

           @OneToMany
           (
           mappedBy = "id",
           targetEntity = TrainingRequest.class,
           fetch = FetchType.EAGER,
           cascade = CascadeType.ALL
           )
           private Set<TrainingRequest> trainingRequests;
          


          code from TrainingRequest
           @ManyToOne()
           @JoinColumn
           (
           name = "user_id",
           nullable = false,
           updatable = false
           )
           private User user;
          


          db output from mysql
          mysql> show tables;
          +------------------+
          | Tables_in_test |
          +------------------+
          | trainingrequests |
          | users |
          +------------------+
          2 rows in set (0.00 sec)
          
          mysql> desc users;
          +----------+--------------+------+-----+---------+----------------+
          | Field | Type | Null | Key | Default | Extra |
          +----------+--------------+------+-----+---------+----------------+
          | user_id | bigint(20) | NO | PRI | NULL | auto_increment |
          | password | varchar(255) | YES | | NULL | |
          | username | varchar(255) | YES | | NULL | |
          +----------+--------------+------+-----+---------+----------------+
          3 rows in set (0.01 sec)
          
          mysql> desc trainingrequests;
          +--------------------+--------------+------+-----+---------+----------------+
          | Field | Type | Null | Key | Default | Extra |
          +--------------------+--------------+------+-----+---------+----------------+
          | trainingrequest_id | bigint(20) | NO | PRI | NULL | auto_increment |
          | cost | double | YES | | NULL | |
          | subject | varchar(255) | YES | | NULL | |
          | summary | varchar(255) | YES | | NULL | |
          | user_id | bigint(20) | NO | MUL | NULL | |
          +--------------------+--------------+------+-----+---------+----------------+
          5 rows in set (0.00 sec)