Reputation: 2477
I have a fairly simple Many to One relationship between two classes:
@Entity
public class Schedule
implements java.io.Serializable {
private String scheduleName;
private HashSet<Step> steps;
@OneToMany(mappedBy="schedule", cascade=CascadeType.ALL,
fetch=FetchType.EAGER)
public HashSet<Step> getSteps() {
return steps;
}
}
@Entity
public class Step implements java.io.Serializable {
private Long id;
private String duration;
private String stepType;
private Schedule schedule;
@ManyToOne(fetch=FetchType.LAZY)
public Schedule getSchedule() {
return schedule;
}
@Id
@GeneratedValue
public Long getId() {
return id;
}
}
Hibernate generates the following tables (in Postgres)
Table "public.schedule"
Column | Type | Modifiers
--------------+------------------------+-----------
uuid | character varying(255) | not null
version | integer |
schedulename | character varying(255) |
steps | bytea |
Table "public.step"
Column | Type | Modifiers
---------------+------------------------+-----------
id | bigint | not null
duration | character varying(255) |
steptype | character varying(255) |
temperature | numeric(19,2) |
schedule_uuid | character varying(255) |
The step table is what I expect, but I don't understand why the steps(bytea) column is there. Am I doing something wrong in my mapping or do I just not understand how hibernate works?
Upvotes: 3
Views: 13220
Reputation: 570575
I suspect the problem is that you're using a concrete HashSet
instead of the Set
interface. Try this (assuming it has an Id
somewhere):
@Entity
public class Schedule implements java.io.Serializable {
private String scheduleName;
private Set<Step> steps = new HashSet<Step>();
@OneToMany(mappedBy="schedule", cascade=CascadeType.ALL, fetch=FetchType.EAGER)
public Set<Step> getSteps() {
return steps;
}
// other properties, getters, setters
}
Also note how I initialized the steps property. Let me quote the documentation about this:
6.1. Persistent collections
...
Notice how the instance variable was initialized with an instance of HashSet. This is the best way to initialize collection valued properties of newly instantiated (non-persistent) instances. When you make the instance persistent, by calling persist() for example, Hibernate will actually replace the HashSet with an instance of Hibernate's own implementation of Set.
And make sure that:
@Id
property (the part you're showing is not enough to confirm that).Step
is implementing equals
/hashCode
correctly (see the references below).Update: Can't reproduce (I don't have PostgreSQL installed by I don't think it is that relevant). I used the following entities:
@Entity
public class Step implements java.io.Serializable {
private Long id;
private String duration;
private String stepType;
private Schedule schedule;
@ManyToOne(fetch = FetchType.LAZY)
public Schedule getSchedule() { return schedule; }
@Id @GeneratedValue
public Long getId() { return id; }
// getters, setters, equals, hashCode
}
And:
@Entity
public class Schedule implements java.io.Serializable {
private Long id;
private String scheduleName;
private Set<Step> steps = new HashSet<Step>();
@OneToMany(mappedBy = "schedule", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public Set<Step> getSteps() { return steps; }
@Id @GeneratedValue
public Long getId() { return id; }
// getters, setters
}
Here is the generated DDL:
create table Schedule (
id bigint generated by default as identity (start with 1),
scheduleName varchar(255),
primary key (id)
)
create table Step (
id bigint generated by default as identity (start with 1),
duration varchar(255),
stepType varchar(255),
schedule_id bigint,
primary key (id)
)
alter table Step
add constraint FK277AEC7B775928
foreign key (schedule_id)
references Schedule
I don't even understand how you could use a HashSet
in your OneToMany
, Hibernate complained (as expected to be honest) when I tried:
Caused by: org.hibernate.AnnotationException: Illegal attempt to map a non collection as a @OneToMany, @ManyToMany or @CollectionOfElements: com.stackoverflow.q4083744.Schedule.steps
Upvotes: 6