当前位置: 首页 > 面试题库 >

在Spring Data JPA存储库方法查询上附加自定义条件

危阳
2023-03-14
问题内容

简洁版本

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

完整版

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

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

public class OwnerAwareEntity implements Serializable {

 private String ownerRef;

}

扩展OwnerAwareEntity的客户实体

public class Customer extends OwnerAwareEntity {

  private String firstname;

  private String mobile ;

}

扩展OwnerAwareEntity的产品实体

public class Product extends OwnerAwareEntity {

  private String code;

  private String name;

}

产品和客户的存储库类,用于扩展OwnerAwareRepository

public interface OwnerAwareRepository extends JpaRepository {

}

public interface ProductRepository extends OwnerAwareRepository {

  Product findByCode(String code );

}

public interface CustomerRepository extends OwnerAwareRepository {

  Customer findByFirstname(String firstname );

}

执行时,这将导致如下查询

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时进行此追加。


问题答案:

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

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

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;

}

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

接下来,为类型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> {

}

创建了一个Aspect将拦截扩展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获取当前的hibernate会话,并使用参数值“
ownerRef”启用过滤器。

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

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

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

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

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

依存关系

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

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

优点

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

注意事项

  • 删除或更新的where子句不受
    此过滤器的影响。

  • 如果存储库包含一个save / update / delete方法,并且该
    方法未标记为@Transactional,则拦截器将给出
    错误信息(在这种
    情况下,您可以捕获并让方法正常进行)



 类似资料:
  • 问题内容: 我正在尝试从Spring指南创建一个自定义查询:根据参考4.4自定义实现,使用REST访问MongoDB数据。但是我的自定义方法在存储库的REST接口(/ user / search)中不可用。 (例如,浏览器无法找到localhost:8080 / user / search / GetByKidsAge?age = 1) 有人可以帮我解决这个问题并给我一些建议吗?非常感谢 !! 下

  • 并将其添加到主存储库: 启动应用程序时,出现以下错误: 原因:org.SpringFramework.Data.Mapping.PropertyReferenceException:未找到类型Friends的属性findFriends!在org.springframework.data.mapping.propertypath.(propertypath.java:77)在org.springfr

  • 在我的项目中有几个实体具有相同的属性(对于示例'name'),所以,有可能创建一个存储库,其中使用自定义的select(实体)?因此,我从JpaRepository扩展了我的存储库,我扩展了MyCustomJpaRepository,MyCustomJpaRepository也扩展了JpaRepository,使其能够从JpaRepository授予基本功能? TKS

  • 我使用jpa存储库进行自定义查询。但我发现了错误 错误日志: 通过字段“login service”表示的不满足的依赖关系;嵌套异常为org.springframework.beans.factory.unsatisfieddependencyexception:创建名为“login service”的bean时出错:通过字段“login serviceimpl”表示的不满足依赖项;嵌套异常为or

  • 使用Spring Boot应用程序。我有一个类UserService,我在其中创建了一个动态查询,根据请求参数具有多个or条件: 我有UserRepository接口,我需要执行这个查询。到目前为止,我使用了findById等JPA函数或@Query(“从事件中选择id”)。 如何将此查询从服务类传递到存储库并执行它?

  • 假设我想有一个方法,它是获得超级主要客户,它有。 其中声明了方法。 然后我的公开存储库界面变成以下内容: 它扩展了和my。 我写的 bot不知道,在实现中写什么。如何接触客户?