在Spring Data JPA存储库方法查询上附加自定义条件 [英] Appending custom conditions on spring data jpa repository method queries

查看:119
本文介绍了在Spring Data JPA存储库方法查询上附加自定义条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简短版本

我正在寻找一种使存储库类的所有findBy方法附加特定条件的方法

I am looking for a way to have all the findBy methods of a repository class appended with a particular condition

完整版本

假设我有一个Product实体和一个Customer实体.它们都扩展了OwnerAwareEntity,并且它们都继承了ownerRef字段,该字段标识实体的所有者(它可以是商家或合作伙伴).我想在运行时修改Product和Customer的findBy方法,以便它们附加有ownerRef的附加条件.可以从用户会话中识别ownerRef值.

Let's assume I have a Product entity and Customer entity. Both of them extends the OwnerAwareEntity and they inherit ownerRef field which identifies the owner of the entity( It could be a merchant or a partner ). I want to have the findBy methods of the Product and Customer modified in runtime such that they are appended with an additional condition of the ownerRef. The ownerRef value could be identified from the user session.

示例

提供公共ownerRef字段的父实体类

The parent entity class that provides the common ownerRef field

public class OwnerAwareEntity implements Serializable {

 private String ownerRef;

}

扩展OwnerAwareEntity的客户实体

Customer entity extending OwnerAwareEntity

public class Customer extends OwnerAwareEntity {

  private String firstname;

  private String mobile ;

}

扩展OwnerAwareEntity的产品实体

Product entity extending OwnerAwareEntity

public class Product extends OwnerAwareEntity {

  private String code;

  private String name;

}

产品和产品目录的存储库类客户扩展OwnerAwareRepository

Repository class for Product & Customer extending an OwnerAwareRepository

public interface OwnerAwareRepository extends JpaRepository {

}

public interface ProductRepository extends OwnerAwareRepository {

  Product findByCode(String code );

}

public interface CustomerRepository extends OwnerAwareRepository {

  Customer findByFirstname(String firstname );

}

这在执行时会导致如下查询

This, when executed, should result in a query like below

select P from Product P where P.code=?1 and P.ownerRef='aValue'
&
select C from Customer C where C.firstname=?1 and C.ownerRef='aValue'

要实现这种条件附加,我应该采取什么方法?我只希望在父存储库为OwnerAwareRepository时进行此添加.

What should be my approach to have this appending of condition achieved?. I only want this appending to be happening when the parent repository is OwnerAwareRepository.

推荐答案

TL; DR::我使用了Hibernate的@Filter,然后创建了一个Aspect来拦截方法

TL;DR: I used @Filter of Hibernate and then created an Aspect to intercept the methods

定义具有以下结构的基类实体

Defined a base class entity with the following structure

OwnerAwareEntity.java

import org.hibernate.annotations.Filter;
import org.hibernate.annotations.FilterDef;
import org.hibernate.annotations.ParamDef;    
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import java.io.Serializable;

@MappedSuperclass
@FilterDef(name = "ownerFilter", parameters = {@ParamDef(name = "ownerRef", type = "long")})
@Filter(name = "ownerFilter", condition = "OWNER_REF = :ownerRef")
public class OwnerAwareEntity implements Serializable{

    @Column(name = "OWNER_REF",nullable = true)
    private Long ownerRef;

}

我们对此实体设置了过滤器.休眠@Filter允许我们设置要附加到select where子句的条件.

We set the filter on this entity. The hibernate @Filter allows us to set a condition to be appended to the select where clause.

接下来,为OwnerAwareEntity类型的实体定义一个基础存储库

Next, defined a base repository for the entity of type OwnerAwareEntity

OwnerAwareRepository.java

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.NoRepositoryBean;

@NoRepositoryBean
public interface OwnerAwareRepository<T, ID extends java.io.Serializable> extends JpaRepository<T, ID> {

}

创建了一个方面,该方面将拦截扩展OwnerAwareRepository的存储库中的所有方法

Created an Aspect that will intercept all the methods from the repositories that extend OwnerAwareRepository

OwnerFilterAdvisor.java

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.hibernate.Filter;
import org.hibernate.Session;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

@Aspect
@Component
@Slf4j
public class OwnerFilterAdvisor {

    @PersistenceContext
    private EntityManager entityManager;

    @Pointcut("execution(public * com.xyz.app.repository.OwnerAwareRepository+.*(..))")
    protected void ownerAwareRepositoryMethod(){

    }

    @Around(value = "ownerAwareRepositoryMethod()")
    public Object enableOwnerFilter(ProceedingJoinPoint joinPoint) throws Throwable{

        // Variable holding the session
        Session session = null;

        try {

            // Get the Session from the entityManager in current persistence context
            session = entityManager.unwrap(Session.class);

            // Enable the filter
            Filter filter = session.enableFilter("ownerFilter");

            // Set the parameter from the session
            filter.setParameter("ownerRef", getSessionOwnerRef());

        } catch (Exception ex) {

            // Log the error
            log.error("Error enabling ownerFilter : Reason -" +ex.getMessage());

        }

        // Proceed with the joint point
        Object obj  = joinPoint.proceed();

        // If session was available
        if ( session != null ) {

            // Disable the filter
            session.disableFilter("ownerFilter");

        }

        // Return
        return obj;

    }


    private Long getSessionOwnerRef() {

// Logic to return the ownerRef from current session

    }
}

顾问程序设置为拦截扩展OwnerAwareRepository的类中的所有方法.在侦听时,从(当前持久性上下文的)entityManager获取当前的休眠会话,并使用参数值"ownerRef"启用过滤器.

The advisor is set to intercept all the methods from classes that extends the OwnerAwareRepository. On the interception, the current hibernate Session is obtained from entityManager ( of current persistence context ) and the filter is enabled with the param value of "ownerRef".

还创建了一个配置文件以对顾问程序进行扫描

Also have a configuration file created to have the advisor scanned

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan(basePackages = {"com.xyz.app.advisors"})
public class AOPConfig {
}

这些文件到位后,您需要对需要了解所有者的实体进行以下操作

Once these files are in place, you need to have the following things done for the entities that need to be owner aware

  1. 实体需要扩展OwnerAwareEntity
  2. 实体存储库类需要扩展OwnerAwareRepository

依赖项

此设置要求spring aop处于依赖关系中.您可以将以下内容添加到pom.xml

This setup requires the spring aop to be in the dependencies. You may add the following to the pom.xml

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

优势

  1. 处理所有选择查询(findBy方法,findAll等)
  2. @Query方法也被拦截
  3. 简单实施

注意事项

  • 删除或更新的where子句不受
    的影响 这个过滤器.
  • 如果存储库包含保存/更新/删除方法,并且
    方法未标记为@Transactional,则拦截器将给出
    错误(您可以在这些错误中捕获并让方法正常进行
    例)
  • The where clause of delete or update is not affected by
    this filter.
  • If the repository contains a save/update/delete method and if the
    method is not tagged as @Transactional, then interceptor will give
    error ( You can catch and have the method proceed normally in these
    cases)

这篇关于在Spring Data JPA存储库方法查询上附加自定义条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆