如何阻止Hibernate为视图子类的继承层级生成Union查询
问题描述
使用TABLE_PER_CLASS继承策略定义了以下实体类:
@Entity(name = "A") @Table(name = "A") @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public class A { @Id @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; // 其他字段 } @Entity(name = "B") @Table(name = "B") public class B extends A { // 其他字段 }
其中表B是一个视图,且每个实体对应一个Repository:
@Repository public interface ARepository extends JpaRepository<A, Integer>, JpaSpecificationExecutor<A> { } @Repository public interface BRepository extends JpaRepository<B, Integer>, JpaSpecificationExecutor<B> { }
需求:调用aRepository.findAll()时禁用Union查询,确保结果无重复,且必须使用Specification API。另外@Polymorphism自6.2版本起已弃用,尝试后无法生效。
解决方案
1. 用Specification限制仅查询父类实体
利用JPA Criteria API的type()表达式,在Specification中明确指定只查询A类型的实体,Hibernate会直接生成针对A表的单表查询,不会触发Union操作。示例代码:
Specification<A> onlyASpec = (root, query, cb) -> cb.equal(root.type(), cb.literal(A.class)); List<A> result = aRepository.findAll(onlyASpec);
该方案完全符合使用Specification API的要求,无需修改实体结构或Repository定义。
2. 自定义Repository实现类(备选)
如果需要更灵活的控制,可以为ARepository编写自定义实现,直接构建仅针对A表的CriteriaQuery:
// 自定义接口 public interface ARepositoryCustom { List<A> findAllOnlyFromA(); } // 实现类 @Repository public class ARepositoryImpl implements ARepositoryCustom { @PersistenceContext private EntityManager em; @Override public List<A> findAllOnlyFromA() { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<A> query = cb.createQuery(A.class); Root<A> root = query.from(A.class); query.select(root); return em.createQuery(query).getResultList(); } } // 修改ARepository继承自定义接口 public interface ARepository extends JpaRepository<A, Integer>, JpaSpecificationExecutor<A>, ARepositoryCustom { }
调用aRepository.findAllOnlyFromA()即可获取仅来自A表的数据,避免Union查询。
3. 调整实体关联方式(彻底规避继承问题)
如果业务允许,可将B与A的继承关系改为关联关系(如@OneToOne),彻底消除继承带来的多表Union逻辑。但此方案需要调整实体结构,适合可重构的场景。
内容的提问来源于stack exchange,提问作者Adrian Florin
相关产品推荐
相关产品推荐

