Hibernate引用MappedSuperclass父类报错,如何指定映射为子类实体?
问题根因
@MappedSuperclass 标注的类仅用于抽取实体公共属性,本身不属于Hibernate管理的实体类型,不能直接作为关联属性的类型使用,因此会触发'Basic' attribute type should not be 'Mapped Superclass'报错。
解决方案
方案1:将公共父类调整为实体类型(推荐)
该方案不需要额外配置关联元数据,新增子类时无感知,适配性更强。
步骤1:修改DBObject父类注解
将原@MappedSuperclass替换为@Entity,同时指定继承策略:
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public abstract class DBObject { @Id @GeneratedValue private Long id; // 原有getter、setter保持不变 }
两种常用继承策略说明:
InheritanceType.TABLE_PER_CLASS:每个子类对应独立物理表,字段结构清晰,跨子类查询时会自动做多表union,性能略低。InheritanceType.SINGLE_TABLE:所有子类共用同一张表,通过歧视字段区分实体类型,查询效率更高,会存在大量空字段,需要额外添加@DiscriminatorColumn配置类型区分字段。
步骤2:给关联属性添加关联注解
根据业务关联关系添加@OneToOne或者@ManyToOne注解即可:
@Entity public class Person extends DBObject { @ManyToOne(fetch = FetchType.LAZY) // 单对单关联时替换为@OneToOne private DBObject shirt; // 原有getter、setter保持不变 }
方案2:保留@MappedSuperclass注解(兼容原有设计)
如果不能修改原有父类的@MappedSuperclass设计,可以使用Hibernate原生的@Any注解实现动态跨实体关联:
步骤1:在父类上添加关联元数据定义
@AnyMetaDef( name = "DBObjectMeta", metaType = "string", idType = "long", metaValues = { @MetaValue(value = "TShirt", targetEntity = TShirt.class), @MetaValue(value = "PoloShirt", targetEntity = PoloShirt.class) // 所有继承DBObject的子类都需要在这里添加对应映射 } ) @MappedSuperclass public abstract class DBObject { @Id @GeneratedValue private Long id; }
步骤2:给关联属性添加@Any注解
@Entity public class Person extends DBObject { @Any(metaDef = "DBObjectMeta", metaColumn = @Column(name = "shirt_entity_type")) @JoinColumn(name = "shirt_id") private DBObject shirt; }
该方案会在Person表中额外新增shirt_entity_type和shirt_id两个字段,分别存储关联的实体类型标识和主键ID,缺点是每次新增DBObject子类都需要手动补充@MetaValue配置。
内容的提问来源于stack exchange,提问作者Abdullah Gheith
相关产品推荐
相关产品推荐

