You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

父类@Where(clause = "DELETE_FLAG='N'")注解不生效,子类添加则正常

解决@Where注解在抽象父类不生效的问题

这个问题我之前也碰到过,其实是Hibernate对@Where注解在@MappedSuperclass父类上的继承处理规则导致的——默认情况下,@Where不会从@MappedSuperclass传递到子类实体,所以你在父类加了注解没效果,子类加就正常。下面给你几个可行的解决方案:

方案一:用@FilterDef+@Filter实现全局过滤(推荐)

@Filter注解是可以通过@MappedSuperclass继承的,我们可以在父类定义全局过滤器,所有子类自动生效:

1. 修改抽象父类代码

@Data 
@MappedSuperclass 
@EntityListeners(AuditingEntityListener.class)
// 定义过滤器参数
@FilterDef(name = "deletedFilter", parameters = @ParamDef(name = "deleteFlag", type = "string"))
// 指定过滤条件
@Filter(name = "deletedFilter", condition = "DELETE_FLAG = :deleteFlag")
public abstract class AuditedEntity extends BaseEntity {
    @CreatedBy private String createUserId;
    @CreatedDate private Date createTime;
    @LastModifiedBy private String lastModifyUserId;
    @LastModifiedDate private Date lastModifyTime;
    // 给默认值,避免null导致过滤失效
    private String deleteFlag = "N"; 
}

2. 启用全局过滤器

在Spring Boot中,我们可以通过配置类全局启用这个过滤器,确保所有查询都自动带上过滤条件:

@Configuration
public class HibernateFilterConfig {
    @Autowired
    private EntityManagerFactory entityManagerFactory;

    @PostConstruct
    public void initGlobalFilters() {
        SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
        // 获取当前会话并启用过滤器,设置默认参数为"N"
        sessionFactory.getCurrentSession().enableFilter("deletedFilter").setParameter("deleteFlag", "N");
    }
}

或者你也可以自定义Spring Data JPA的基础Repository,在通用方法上绑定过滤器,这样更灵活:

@NoRepositoryBean
public interface BaseRepository<T, ID> extends JpaRepository<T, ID> {
    @Override
    @Filter(name = "deletedFilter", condition = "DELETE_FLAG = 'N'")
    List<T> findAll();

    @Override
    @Filter(name = "deletedFilter", condition = "DELETE_FLAG = 'N'")
    Optional<T> findById(ID id);

    // 其他需要过滤的查询方法也可以按此方式添加
}

之后让你的SysCategoryRepository继承这个BaseRepository即可。

方案二:修改父类为@Entity并指定继承策略

如果你的业务允许修改表结构,可以把父类的@MappedSuperclass换成@Entity,然后用@Inheritance指定继承策略,这样@Where注解会被子类继承:

@Data 
@Entity
@Inheritance(strategy = InheritanceType.JOINED) // 或者SINGLE_TABLE,根据业务选择
@EntityListeners(AuditingEntityListener.class)
@Where(clause = "DELETE_FLAG='N'")
public abstract class AuditedEntity extends BaseEntity {
    // 字段保持不变
    @CreatedBy private String createUserId;
    @CreatedDate private Date createTime;
    @LastModifiedBy private String lastModifyUserId;
    @LastModifiedDate private Date lastModifyTime;
    private String deleteFlag = "N";
}

子类的@Entity注解保持不变:

@Entity 
@Data 
@Table(name = "SYS_CATEGORY")
public class SysCategoryEntity extends AuditedEntity {}

这种方式的缺点是会改变数据库表的结构(比如JOINED策略会生成父类表和子类表,查询时关联),如果已有生产数据需要谨慎操作。

为什么@Where在父类不生效?

简单来说,Hibernate的@Where注解是实体级别的注解,它只会作用在直接标注的@Entity类上。而@MappedSuperclass只是用来共享字段映射,不属于实体范畴,所以父类上的@Where不会被子类继承和应用。

验证方法

修改完成后,你可以开启Hibernate的SQL日志,查看查询SysCategoryEntity时生成的SQL语句,应该会自动带上DELETE_FLAG='N'的过滤条件,说明配置生效了。

内容的提问来源于stack exchange,提问作者Belala

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:19:21