在开发我的Spring Boot应用程序时,我不得不放弃我的数据库并让Hibernate再次使用hibernate.hbm2ddl.auto=update
生成它。之后我想确保它完成了我想做的所有事情,所以我打电话给MySQL Workbench来反向工程我的整个数据库。当我这样做时,我注意到由于某种原因,我的架构中有两倍的表。我的表中有很多实体关系,但它们都是一对多的,但由于某种原因,几乎所有的一对多关系Hibernate都生成了多对多的连接表。这让我感到意外,因为在使用相同的Web应用程序之前并没有这样做。
我对SO的搜索只引发了this这个似乎无关紧要的问题。
现在我将提供样本,但我有很多代码,我想保持简短,所以我将只剪切一个例子。如果您需要了解更多信息,请在答案中注明。
所以,例如,我有这个实体:
@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
}
您可以看到此实体引用自身。技能在这里是一棵树。因此,Hibernate将其解释为:
事实上,skill_skill
表甚至没有被使用。您可以看到skill
在没有此表的情况下仍然引用自身。当我在此表中插入新数据时,skill_skill
中不会显示任何新内容。虽然这两个实体由于某种原因没有得到额外的表:
这两个对象在这里有单边关系:
@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;
}
我可以思考的一些原因:
AbstractDomainObject
超类。它只具有保护的样板功能。之前它没有造成任何问题。@Cascade({CascadeType.DETACH})
注释。虽然看起来不太可能。@EnableAutoConfiguration
更改为@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})
的原因。可能是Hibernate现在表现得有些不同吗? 答案 0 :(得分:4)
这里有一个双向关联,双方都是所有者,基本上将它转变为两个独立的关联。在一对多关联中,所有者通常是多方(注意mappedBy
属性):
OneToMany(fetch = FetchType.EAGER, targetEntity = Skill.class, mappedBy = "parent")
@Cascade({CascadeType.DETACH})
private Set<Skill> children;
这样,Hibernate在维护关系时会忽略一对(并且不会创建连接表,这是没有@OneToMany
的{{1}}关联的默认配置。
答案 1 :(得分:2)
如果你使用@OneToMany
而没有@JoinColumn
Hibernate创建一个连接表
@OneToMany(fetch = FetchType.EAGER, targetEntity = Skill.class)
@Cascade({CascadeType.DETACH})
private Set<Skill> children;
将其更改为
@OneToMany(fetch = FetchType.EAGER)
@Cascade({CascadeType.DETACH})
@JoinColumn
private Set<Skill> children;
请不要使用不必要的映射属性 - targetEntity = Skill.class
我不确定您是否需要使用此关联
private Skill parent;
使用User
关联关联Role
和@OneToMany
是不正确的,因为User
可以有多个角色,每个角色可以属于多个用户。使用@ManyToMany
进行此类关联。