使用 SingleTable 进行休眠继承

Posted

技术标签:

【中文标题】使用 SingleTable 进行休眠继承【英文标题】:Hibernate inheritance with SingleTable 【发布时间】:2017-03-12 10:18:31 【问题描述】:

我尝试用 hibernate 5.2 实现单表继承。 基类

@Entity 
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="type", discriminatorType= DiscriminatorType.STRING)
@DiscriminatorValue("HAKSAHIBI")
@DiscriminatorOptions(force=true)
public class PropertyOwner implements  implements Serializable
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    long id;
    @ManyToOne 
    Property property;
   @ManyToOne
 Person person; 


作者类扩展了 PropertyOwner:

@Entity 
@DiscriminatorValue("AUTHOR")
class Author extends PropertyOwner 

Composer 类扩展 PropertyOwner:

@Entity 
@DiscriminatorValue("COMPOSER")
class Composer extends PropertyOwner 

人物类:

public class Person 
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    long id;
String title; 

属性类

public class Property
    @Id 
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    long id;
String title; 

@OneToMany
Set<Composer> composers = new HashSet<Composer>();

@OneToMany
Set<Author> authors = new HashSet<Author>(); 

我希望表结构如下:

CREATE TABLE `Property` (
  `id` bigint(20) NOT NULL,
  `title` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `Person` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `title` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

CREATE TABLE `PropertyOwner` (
  `type` varchar(31) NOT NULL,
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `property_id` bigint(20) DEFAULT NULL,
  `person_id` bigint(20) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK77apjkkl14xwe45rs1ocgtt4u` (`property_id`),
  KEY `FKqagfofgupovfly26enivfhm3j` (`person_id`),
  CONSTRAINT `FK77apjkkl14xwe45rs1ocgtt4u` FOREIGN KEY (`property_id`) REFERENCES `property` (`id`),
  CONSTRAINT `FKqagfofgupovfly26enivfhm3j` FOREIGN KEY (`person_id`) REFERENCES `person` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

但不幸的是,它使用以下语句为 Author 和 Composer 类创建了另一个表

CREATE TABLE `property_propertyOwner` (
  `Property_id` bigint(20) NOT NULL,
  `author_id` bigint(20) NOT NULL,
  `composer_id` bigint(20) NOT NULL,
  UNIQUE KEY `UK_rv9fxc06rcydqp6dqpqbmrkie` (`author_id`),
  UNIQUE KEY `UK_fm4v55i021l5smuees0vs3qmy` (`composer_id`),
  KEY `FKt3yqcltkd0et8bj08ge0sgrqb` (`Property_id`),
  CONSTRAINT `FK1pj2606cjxrb70ps89v7609hg` FOREIGN KEY (`author_id`) REFERENCES `PropertyOwner` (`id`),
  CONSTRAINT `FKfdh3r95jffvd07u3xn21824r7` FOREIGN KEY (`composer_id`) REFERENCES `PropertyOwner` (`id`),
  CONSTRAINT `FKt3yqcltkd0et8bj08ge0sgrqb` FOREIGN KEY (`Property_id`) REFERENCES `Property` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

我做错了什么?我期望不应该创建 property_PropertyOwner 表,并且 Author , Composer 类信息应该保存在 propertyOwner 表中。

注意:我尝试了枚举注释,但这次在 Property 类中我无法定义 Setauthor 字段,我必须定义 Set 并将枚举信息添加到该对象。 提前致谢 。

【问题讨论】:

您的映射中似乎缺少mappedBy。使用@OneToMany(mappedBy = "property")@OneToMany(mappedBy = "person") 【参考方案1】:

在您的财产实体中拥有多个子类(作曲家和作者)关联是没有意义的。因为您具有单表继承,即您的财产所有者表将具有 property_id 的外键。 因此,您可以拥有单一关联。

@OneToMany
Set<PropertyOwner> composers = new HashSet<PropertyOwner>();

您可以使用 DiscriminatorColumn 类型将此集合拆分为内存中的作者和作曲家。

【讨论】:

由于性能问题,我想在属性和数据库中使用 Author 和 Composer 对象,单个表会保存数据。如果我更改 PropertyOwner,我不能将 Author 用作对象。 由于您使用单表继承,您将在属性实体中获得作者或作曲家对象。 Hibernate 将根据鉴别器值将其转换为适当的子类对象。

以上是关于使用 SingleTable 进行休眠继承的主要内容,如果未能解决你的问题,请参考以下文章

在休眠中使用继承时如何仅获取一种实体?

休眠:@EmbeddedId、继承和@SecondaryTable

单表继承(休眠)的 JPA 2 标准查询

我需要帮助来实现特定的休眠继承映射

我可以在休眠中使用单表继承从扩展实体中选择所有超级对象吗?

如何在休眠中不继承 Id GeneratedValue(在子类中禁用 @GeneratedValue)