Hibernate @Filter不适用于Spring JpaRepository.findById方法

kxkpmulp  于 2023-06-23  发布在  Spring
关注(0)|答案(2)|浏览(146)

为了创建行级授权,我想结合使用spring-dataJpaRepository<T, ID>接口使用@Filter@FilterDef hibernate注解。假设我们有以下实体:

@Entity
public class User {
   @Id
   private Long id;
   private String name;
    
   @ManyToOne
   private Pharmacy pharmacy;
}
    
@Entity
public class Pharmacy {
   @Id
   private Long id;
   private String name;
}

我想根据向服务器发送请求的人创建授权。为此,我在Pharmacy实体的顶部添加了@Filter@FilterDef注解。所以,药房应该像下面这样:

@Entity
@FilterDef(name = "pharmacyFilter", parameters = {@ParamDef(name = "userId", type = "long")})
@Filters({
   @Filter(name = "pharmacyFilter", condition = "id in (select user.pharmacy_id from user where user.id = :userId)")
})
public class Pharmacy {
   //...
}

我为访问数据库创建的存储库如下所示:

@Repository
public interface PharmacyRepository extends JpaRepository<Pharmacy, Long> {
    
}

当我启用pharmacyFilter时,一切正常,过滤器应用于所有查询。您可以看到为repository.findAll()生成的查询如下:

select pharmacy0_.id as id1_0_, pharmacy0_.name as name2_0_ from pharmacy pharmacy0_ where pharmacy0_.id in (select user.pharmacy_id from user where user.id = ?)

但是,当我想尝试使用repository.findById(ID id)时,问题发生了。当我使用上面提到的方法时,过滤器不会应用到最终的查询中,我们会在终端中看到下面的SQL:

select pharmacy0_.id as id1_0_0_, pharmacy0_.name as name2_0_0_ from pharmacy pharmacy0_ where pharmacy0_.id=?

我猜这个问题是由于多次使用id造成的。一个在findById中,另一个在过滤条件中。但是当我尝试使用session对象创建查询时,这个问题没有发生,输出是理想的:

select pharmacy0_.id as id1_0_, pharmacy0_.name as name2_0_ from pharmacy pharmacy0_ where pharmacy0_.id in (select user.pharmacy_id from user where user.id = ?) and pharmacy0_.id=2

使用以下方法可以解决这个问题,但是当我们使用JpaRepository#findById默认实现时会发生什么呢?

@Query(value = "from Pharmacy where id = :id")
Optional<Pharmacy> findById(Long id);

先谢谢你了。

zy1mlcev

zy1mlcev1#

正如hibernate文档中所述:
过滤器适用于实体查询,但不适用于直接获取。
但在引擎盖下,repository.findById(ID id)方法调用EntityManager.find。所以,这是预期的行为。

sc4hvdpw

sc4hvdpw2#

Hi there try this will apply any filter by bypass默认springboot findById

@Repository
public interface PharmacyRepository extends JpaRepository<Pharmacy, Long> {
    

   @Override
    default Optional<Pharmacy> findById(Long id) {
        return findOne(Example.of(Pharmacy.builder().id(id).build()));
        // or with predicate
    }
}

相关问题