如何使用 Hibernate 为 Spring data JPA 的所有查找方法添加全局 where 子句?
Posted
技术标签:
【中文标题】如何使用 Hibernate 为 Spring data JPA 的所有查找方法添加全局 where 子句?【英文标题】:How to add global where clause for all find methods of Spring data JPA with Hibernate? 【发布时间】:2018-02-07 17:24:55 【问题描述】:我们正在开发使用带有休眠功能的 Spring data JPA 的 Web 应用程序。
在应用程序中,每个实体都有一个compid字段。 这意味着在每个 DB 调用(Spring Data 方法)中都必须使用 compid 检查。
我需要一种方法,即“where compid = ?”检查是否为每个查找方法自动注入。 这样我们就不必专门为 compid 检查而烦恼。
这可以通过 Spring Data JPA 框架实现吗?
【问题讨论】:
【参考方案1】:也许Hibernate的注解@Where
会对你有所帮助。它将传递的条件添加到与实体相关的任何 JPA 查询中。例如
@Entity
@Where(clause = "isDeleted='false'")
public class Customer
//...
@Column
private Boolean isDeleted;
更多信息:1、2
【讨论】:
感谢您的回复,但在@Where 注释中,我必须在每个实体类上添加它。我想避免这种机制。有可能这样做吗?哪里 repo.findAll(); 您有所有此类实体的基超类吗?您可以将字段compid
和 @Where
注释移到那里...
“通用查询增强”存在一个未解决的问题,这是您所追求的功能类型,但进展不大jira.spring.io/browse/DATACMNS-293。我认为添加到超类的 @Where
注释是最好的选择 - 因为它是特定于 Hibernate 的注释,它不适用于 Spring Data 存储库,因此它需要在实体上运行。
@Zeeshan 不要忘记接受/支持答案))【参考方案2】:
就像其他人说的那样,没有设置方法
一种选择是通过示例查看查询 - 来自 spring 数据文档 -
Person person = new Person();
person.setFirstname("Dave");
Example<Person> example = Example.of(person);
因此您可以在对象或父 JPA 对象中默认为 compid
另一个选项是自定义存储库
【讨论】:
【参考方案3】:同意 Abhijit Sarkar。
您可以通过休眠侦听器和方面来实现您的目标。我可以提出以下建议:
创建一个注解@Compable
(或任何你称之为的)来标记服务方法
创建应该是 bean 和 @Aspect
的 CompAspect。它应该有这样的东西
@Around("@annotation(compable)")`
public Object enableClientFilter(ProceedingJoinPoint pjp, Compable compable) throws Throwable
Session session = (Session) em.getDelegate();
try
if (session.isOpen())
session.enableFilter("compid_filter_name")
.setParameter("comp_id", your_comp_id);
return pjp.proceed();
finally
if (session.isOpen())
session.disableFilter("filter_name");
em - EntityManager
3)您还需要提供休眠过滤器。如果你使用注解,它可能看起来像这样:
@FilterDef(name="compid_filter_name", parameters=@ParamDef(name="comp_id", type="java.util.Long"))
@Filters(@Filter(name="compid_filter_name", condition="comp_id=:comp_id"))
所以你的条件where compid = ?
将是下面的@Service
方法
@Compable
someServicweMethod()
List<YourEntity> l = someRepository.findAllWithNamesLike("test");
Selects 基本上就是这样,
对于更新/删除,此方案需要 EntityListener
。
【讨论】:
【参考方案4】:我可以贡献 50% 的解决方案。 50% 因为似乎不容易包装Query Methods。自定义 JPA 查询也是这种全局方法的一个问题。如果标准查找器足够,则可以扩展自己的SimpleJpaRepository
:
public class CustomJpaRepositoryIml<T, ID extends Serializable> extends
SimpleJpaRepository<T, ID>
private JpaEntityInformation<T, ?> entityInformation;
@Autowired
public CustomJpaRepositoryIml(JpaEntityInformation<T, ?> entityInformation,
EntityManager entityManager)
super(entityInformation, entityManager);
this.entityInformation = entityInformation;
private Sort applyDefaultOrder(Sort sort)
if (sort == null)
return null;
if (sort.isUnsorted())
return Sort.by("insert whatever is a default").ascending();
return sort;
private Pageable applyDefaultOrder(Pageable pageable)
if (pageable.getSort().isUnsorted())
Sort defaultSort = Sort.by("insert whatever is a default").ascending();
pageable = PageRequest.of(pageable.getPageNumber(), pageable.getPageSize(), defaultSort);
return pageable;
@Override
public Optional<T> findById(ID id)
Specification<T> filterSpec = filterOperatorUserAccess();
if (filterSpec == null)
return super.findById(id);
return findOne(filterSpec.and((Specification<T>) (root, query, criteriaBuilder) ->
Path<?> path = root.get(entityInformation.getIdAttribute());
return criteriaBuilder.equal(path, id);
));
@Override
protected <S extends T> TypedQuery<S> getQuery(Specification<S> spec, Class<S> domainClass, Sort sort)
sort = applyDefaultOrder(sort);
Specification<T> filterSpec = filterOperatorUserAccess();
if (filterSpec != null)
spec = (Specification<S>) filterSpec.and((Specification<T>) spec);
return super.getQuery(spec, domainClass, sort);
这个实现被拾取,例如通过将其添加到 Spring Boot:
@SpringBootApplication
@EnableJpaRepositories(repositoryBaseClass = CustomJpaRepositoryIml.class)
public class ServerStart
...
如果您也需要对 Querydsl 进行这种过滤,也可以实现并注册 QuerydslPredicateExecutor
。
【讨论】:
以上是关于如何使用 Hibernate 为 Spring data JPA 的所有查找方法添加全局 where 子句?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Spring 和 Hibernate 为 Web 应用程序和批处理作业设置事务
如何使用 Hibernate 为 Spring data JPA 的所有查找方法添加全局 where 子句?
使用 spring 和 hibernate 时,如何处理会话/事务?
如何使用 JPQL、Spring Data Repositories 和 Hibernate 为 TimescaleDB `time_bucket` 函数参数化 Postgresql 间隔