While developing my Spring Boot application I had to drop my database and have Hibernate generate it again with hibernate.hbm2ddl.auto=update
. After that I wanted to make sure it did everything like I wanted to so I called MySQL Workbench to reverse engineer my entire database. When I did that, I noticed that for some reason there were twice as many tables in my schema. I have a lot of entity relationships in my table, but all of them are one-to-many, yet for some reason for almost all of my one-to-many relationships Hibernate has generated many-to-many join tables. It came as a surprise to me because this didn't happen before with the same web application.
My search through SO has only led me to this question which seems irrelevant.
Now I will provide samples, but I have a lots of code and I want to keep it short, so I will cut to only one example. If you need to see more, please specify this in your answer.
So, for instance, I have this entity:
@SuppressWarnings("serial")
@Entity
@Indexed
@Table(name = "SKILL")
public class Skill extends AbstractDomainObject {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", nullable = false)
private long id;
//Some properties
@ManyToOne(fetch = FetchType.EAGER, targetEntity = Skill.class)
@JoinColumn(name = "PARENT", nullable = true)
@Cascade({CascadeType.DETACH})
//Cascade annotations are from Hibernate, all else except for
//"Indexed" are from javax.persistence
private Skill parent;
@OneToMany(fetch = FetchType.EAGER, targetEntity = Skill.class)
@Cascade({CascadeType.DETACH})
private Set<Skill> children;
//Getters, setters, etc
}
You can see that this entity references itself. Skills are a tree here. So, Hibernate interprets this as:
In fact, skill_skill
table isn't even being used. You can see that skill
still references itself without this table. When I insert new data in this table, nothing new appears in skill_skill
. Although these two entities for some reason don't get extra table:
These two object have one-side relationship here:
@SuppressWarnings("serial")
@Entity
@Table(name = "ROLE")
public class Role implements DomainObject {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "ID", nullable = false)
private long id;
@Column(name = "ROLENAME", nullable = false, length = 50)
private String rolename;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "OWNER", nullable = false)
private User owner;
}
Some causes I can think on:
- Abstract
AbstractDomainObject
superclass. It only has protected boilerplate functions. It didn't cause any problem before though. @Cascade({CascadeType.DETACH})
annotation that I added. Although seems unlikely.- My last change was that I created a second data source in my project, this is why I changed my
@EnableAutoConfiguration
to@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
. Could it be that Hibernate behaves somehow differently now? - I also moved all my entities causing trouble to a different package.
If you use
@OneToMany
without@JoinColumn
Hibernate creates a join tablechange it to
Please, don't use unnecessary mapping properties —
targetEntity = Skill.class
And I am not sure you need to use this association
It is incorrect to associate
User
andRole
using the@OneToMany
association, because ofUser
can have multiple roles and each role can belong to multiple users. Use@ManyToMany
for such an association.An example of an association between User and Role
What you have here is a bidirectional association in which both sides are owners, turning it basically to two independent associations. In a one-to-many association the owner is usually the many-to side (note the
mappedBy
attribute):This way Hibernate will ignore one-to side when maintaining the relationship (and will not create the join table which is the default configuration for
@OneToMany
association without@JoinColumn
).