小编典典

Hibernate创建冗余的多对多表

spring-boot

在开发Spring
Boot应用程序时,我必须删除数据库,然后让Hibernate用再次生成它hibernate.hbm2ddl.auto=update。之后,我想确保它能够按照我的意愿进行所有操作,因此我调用了MySQL
Workbench对整个数据库进行反向工程。当我这样做时,我注意到由于某种原因,我的架构中的表数量是原来的两倍。我的表中有很多实体关系,但是它们都是一对多的,但是由于某种原因,几乎所有的一对多关系Hibernate都生成了多对多联接表。令我惊讶的是,这在同一个Web应用程序中从未发生过。

我对SO的搜索仅使我想到了这个似乎无关紧要的问题。

现在,我将提供示例,但是我有很多代码,并且我想使其简短一些,因此,我仅介绍一个示例。如果您需要更多信息,请在答案中指定。

因此,例如,我有这个实体:

@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没有此表仍然引用自身。当我在此表中插入新数据时,中没有新内容出现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;
}

我可以考虑一些原因:

  1. 抽象AbstractDomainObject超类。它仅具有受保护的样板功能。以前没有引起任何问题。
  2. @Cascade({CascadeType.DETACH})我添加的注释。虽然似乎不太可能。
  3. 我最后的变化是,我创建了自己的项目中第二个数据源,这就是为什么我改变了我@EnableAutoConfiguration@EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class})。难道是Hibernate现在的行为有所不同吗?
  4. 我还将所有引起麻烦的实体移到了其他程序包中。

阅读 266

收藏
2020-05-30

共1个答案

小编典典

您这里拥有的是双向关联,双方都是所有者,因此基本上将其变成了两个独立的关联。在一对多关联中,所有者通常是多对边(请注意mappedBy属性):

OneToMany(fetch = FetchType.EAGER, targetEntity = Skill.class, mappedBy = "parent")
@Cascade({CascadeType.DETACH})
private Set<Skill> children;

这样,Hibernate在维护关系时将忽略一对一的关系(并且不会创建@OneToMany联接表,这是不使用的关联的默认配置@JoinColumn)。

2020-05-30