I posted this to the EJB3/JPA forum too, but I'm going to post it here too in hopes that it might get spotted more easily. Apologies.
Like another recent poster, I am trying to set up what seems like a very simple one-to-many relationship, but having no luck. When I try to start my application, the validator tells me I'm missing a column. I'm new to Hibernate and Java Persistence, so I suspect I'm missing something basic.
I have a small schema with two tables:
Code:
create table floors (
id integer primary key
);
create table rooms (
floor_id integer,
number integer,
primary key(floor_id, number),
constraint foreign key (floor_id) references floors(id)
);
I also have two entities:
Code:
@Entity
@Table(name="floors")
public class Floor {
private int id;
private List<Room> rooms;
@Id
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@OneToMany(cascade=CascadeType.ALL, mappedBy="floor")
public List<Room> getRooms() {
return rooms;
}
public void setRooms(List<Room> rooms) {
this.rooms = rooms;
}
}
Code:
@Entity
// Remove next line to make validation work
@IdClass(hotel.RoomKey.class)
@Table (name="rooms")
public class Room {
private int floorId;
private int number;
private Floor floor;
// Remove next line to make validation work
@Id
@Column(name="floor_id")
public int getFloorId() {
return floorId;
}
public void setFloorId(int floorId) {
this.floorId = floorId;
}
@Id
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
@ManyToOne
@JoinColumn(name="floor_id", insertable=false, updatable=false)
public Floor getFloor() {
return floor;
}
public void setFloor(Floor floor) {
this.floor = floor;
}
}
I also have a composite key class:
Code:
// Do I need this annotation? It doesn't seem to work either way.
@Embeddable
public class RoomKey implements Serializable {
private static final long serialVersionUID = 4226995603575410303L;
private int floorId;
private int number;
public int getFloorId() {
return floorId;
}
public void setFloorId(int cardSetId) {
this.floorId = cardSetId;
}
public int getNumber() {
return number;
}
public void setNumber(int position) {
this.number = position;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
else if (o instanceof RoomKey) {
return floorId == ((RoomKey)o).getFloorId() &&
number == ((RoomKey)o).getNumber();
}
return false;
}
@Override
public int hashCode() {
return floorId ^ number;
}
}
Finally, my main class tries to create a SessionFactory:
Code:
AnnotationConfiguration config = new AnnotationConfiguration();
config.configure();
sessionFactory = config.buildSessionFactory();
This fails with the following message:
Quote:
Exception in thread "main" java.lang.ExceptionInInitializerError
at hotel.HibernateTest$HibernateUtil.<clinit>(HibernateTest.java:29)
at hotel.HibernateTest.main(HibernateTest.java:13)
Caused by: org.hibernate.HibernateException: Missing column: floorId in hotel.rooms
at org.hibernate.mapping.Table.validateColumns(Table.java:254)
at org.hibernate.cfg.Configuration.validateSchema(Configuration.java:1083)
at org.hibernate.tool.hbm2ddl.SchemaValidator.validate(SchemaValidator.java:116)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:317)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
at hotel.HibernateTest$HibernateUtil.<clinit>(HibernateTest.java:26)
If I remove the two marked lines (the @IdClass and one of the @Id tags) from Room, validation works fine. I guess when I leave them in Hibernate is ignoring my @Column and looking for a column with a default name...? But even if that's so, I don't really understand why. I'm stymied, and I've barely started! Hopefully one of you will be able to diagnose this easily - I'm sure I'm missing something very basic. Thanks in advance for your help!