使用JPA/Hibernate时,抽象类与嵌入式属性关联创建遇阻
解决Hibernate抽象类作为@Embedded属性的实例化错误
老哥你遇到的这个问题我之前排查过,核心是代码里的注解冲突+JPA值类型的限制导致的,咱们一步步拆解解决:
首先说两个关键问题:
- 注解冲突:你给抽象类
Foo同时加了@MappedSuperclass和@Embeddable,这俩注解的定位完全不同:@MappedSuperclass是给实体类当父类用的,用来共享映射属性,它本身既不是实体也不是可嵌入类;@Embeddable是标记一个类可以作为值类型嵌入到实体中。
同时用这俩会让Hibernate彻底搞不清这个类的定位,直接触发后续的实例化报错。
- 抽象类不能作为@Embedded属性类型:JPA规范里,
@Embedded标记的是值类型属性,Hibernate加载数据时需要实例化这个属性的对象,但抽象类本身无法被实例化——哪怕你传入的是子类Poo的实例,Hibernate元数据里只知道属性类型是抽象类Foo,它没办法自动推断该实例化哪个子类。
直接可行的解决方案(JPA标准兼容)
最稳妥的方式是把None类里的属性类型改成具体的子类Poo,这样Hibernate明确知道要实例化的类,就能正常运行了:
// 修正抽象类Foo的注解,只保留@MappedSuperclass作为子类的属性共享父类 @MappedSuperclass public abstract class Foo { // 你的共享属性... } // Poo保持@Embeddable注解,继承Foo @Embeddable public class Poo extends Foo { // Poo的专属属性... } // 修改None的属性类型为具体的Poo @Entity @Table public class None { // 其他属性... @Embedded private Poo foo; public None(Poo foo) { this.foo = foo; } } // 保存代码不需要修改 None none = new None(new Poo()); save(none);
支持多态嵌入的进阶方案(Hibernate扩展)
如果你确实需要让None的属性支持Foo的多个子类,可以用Hibernate提供的多态嵌入扩展(注意:这不是JPA标准,会降低代码的移植性):
// 给抽象类Foo添加@Embeddable和鉴别列,用来区分不同子类 @Embeddable @DiscriminatorColumn(name = "FOO_TYPE") public abstract class Foo { // 共享属性... } // 子类Poo添加鉴别值,标记自己的类型 @Embeddable @DiscriminatorValue("POO") public class Poo extends Foo { // Poo的专属属性... } // None类中保持Foo类型属性,通过@AttributeOverrides指定鉴别列的映射 @Entity @Table public class None { // 其他属性... @Embedded @AttributeOverrides({ @AttributeOverride(name = "fooType", column = @Column(name = "FOO_TYPE")) // 可以在这里覆盖其他属性的列名映射 }) private Foo foo; public None(Foo foo) { this.foo = foo; } }
这种方式下,Hibernate会通过FOO_TYPE列的值来判断要实例化哪个子类,实现多态嵌入的效果。
内容的提问来源于stack exchange,提问作者Marco Queiroz
相关产品推荐
相关产品推荐

