【问题标题】:Hibernate @Filter does not work with Spring JpaRepository.findById methodHibernate @Filter 不适用于 Spring JpaRepository.findById 方法
【发布时间】:2021-05-04 21:48:52
【问题描述】:

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

@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);

提前致谢。

【问题讨论】:

  • 对我来说 findAll() 甚至都不起作用,即使在通过entityManager.unwrap(Session.class).enableFilter("myFilter").setFilterParam("myParam", "myValue"); 显式启用过滤器之后代码被接受,过滤器已启用,我完全按照上面的方式进行操作。但它只是不起作用。条件没有添加到查询中。就此放弃。 :(

标签: java hibernate spring-data


【解决方案1】:

正如休眠中所说的documentation

过滤器适用于实体查询,但不适用于直接获取。

但在后台 repository.findById(ID id) 方法调用 EntityManager.find。 所以,这是预期的行为。

【讨论】:

  • 感谢您的回复。但是,有没有其他方法可以强制不使用EntityManager::find? (而不是我在问题中尝试过的)。
  • 我没有看到另一种方式,因为你可以像你那样编写自己的查询。
  • 这应该在 Hibernate 6 Beta 1 中修复。见hibernate.atlassian.net/browse/HHH-14772
猜你喜欢
  • 2020-03-19
  • 1970-01-01
  • 2014-01-20
  • 1970-01-01
  • 2011-01-22
  • 2016-06-30
  • 2017-10-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多