Hos*_*her 8 java hibernate spring-data
为了创建行级授权,我想结合spring-data接口使用@Filterhibernate注释。假设,我们有以下实体:@FilterDefJpaRepository<T, ID>
@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;
}
Run Code Online (Sandbox Code Playgroud)
我想根据谁向服务器发送请求来创建授权。为此,我在实体顶部添加了@Filter注释。所以,药房应该是这样的:@FilterDefPharmacy
@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 {
//...
}
Run Code Online (Sandbox Code Playgroud)
我创建的用于访问数据库的存储库如下所示:
@Repository
public interface PharmacyRepository extends JpaRepository<Pharmacy, Long> {
}
Run Code Online (Sandbox Code Playgroud)
当我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 = ?)
Run Code Online (Sandbox Code Playgroud)
但是,当我想尝试使用repository.findById(ID id). 当我使用上述方法时,过滤器不会应用于最终查询,我们将在终端中看到以下sql:
select pharmacy0_.id as id1_0_0_, pharmacy0_.name as name2_0_0_ from pharmacy pharmacy0_ where pharmacy0_.id=?
Run Code Online (Sandbox Code Playgroud)
我猜这个问题是由于多次使用 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
Run Code Online (Sandbox Code Playgroud)
使用以下方法可以解决问题,但是当我们使用 JpaRepository#findById 默认实现时会发生什么?
@Query(value = "from Pharmacy where id = :id")
Optional<Pharmacy> findById(Long id);
Run Code Online (Sandbox Code Playgroud)
提前致谢。
正如 hibernate文档中所述:
过滤器适用于实体查询,但不适用于直接获取。
但在幕后repository.findById(ID id)方法调用EntityManager.find。所以,这是预期的行为。