使用Hibernate SINGLE_TABLE策略时Spring JPA查询未带鉴别器条件问题
问题根源与解决办法
你的问题出在继承体系的配置逻辑上:抽象基类不该用@MappedSuperclass,而且@Inheritance、@DiscriminatorColumn的配置位置完全错了。
@MappedSuperclass只是用来复用实体属性的“工具类”,Hibernate不会把它当成继承体系的一部分,自然不会自动处理鉴别器过滤。单表继承的正确姿势是把基类设为实体,把继承和鉴别器规则定义在基类上。
修正后的代码配置
抽象基类 Relation
@Entity @Table(name = "relation") @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "type", discriminatorType = DiscriminatorType.INTEGER) public abstract class Relation { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(columnDefinition = "bigint unsigned", name = "id") public long id; // 别手动赋值type!Hibernate会根据鉴别器自动填充 @Enumerated(EnumType.ORDINAL) @Column(name = "type", insertable = false, updatable = false) protected RelationType type; }
这里要注意:
- 基类必须标记
@Entity,Hibernate才会识别它是继承链的根 type字段加insertable = false, updatable = false,防止手动赋值和Hibernate的自动值冲突- 子类里别再定义
type字段,会搞乱鉴别器逻辑
子类 Ban
@Entity @DiscriminatorValue("0") public class Ban extends Relation { // 子类自己的属性写在这... }
另一个子类(比如允许类)直接把@DiscriminatorValue改成"1"就行,不用重复加@Table,单表继承共享基类的表。
仓库层的正确用法
通用基仓库(可选)
@NoRepositoryBean public interface BaseRelationRepository<T extends Relation> extends JpaRepository<T, Long> { }
Ban专属仓库
public interface BanRepository extends BaseRelationRepository<Ban> { // Spring Data JPA自动生成的查询会自动加鉴别器条件 List<Ban> findAllByUser(User user); // 自定义JPQL也会自动带上鉴别器过滤 @Query("from Ban b where b.user = :user") List<Ban> findAllByUserCustom(@Param("user") User user); }
改完之后,不管是自动生成的查询还是自定义JPQL,Hibernate都会自动在SQL里加上where type = 0的过滤条件,不会再查全表了。
额外提醒
- 确保
RelationType枚举的序号和@DiscriminatorValue完全对应(比如Ban是枚举的第0个值) - 如果要通过基类查所有子类,直接用
JpaRepository<Relation, Long>就行,想过滤某类的话手动加type条件就行
内容的提问来源于stack exchange,提问作者littleAlien
相关产品推荐
相关产品推荐

