hbm.xml to javax.persistence annotations problems
mpurdy1973 Jul 16, 2009 11:18 AMi 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)