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)