使用连接表存储库的@manytomany 中的 Spring 数据 jpa 规范和可分页

Posted

技术标签:

【中文标题】使用连接表存储库的@manytomany 中的 Spring 数据 jpa 规范和可分页【英文标题】:Spring data jpa specification and pageable in @manytomany using join table repository 【发布时间】:2020-07-26 18:36:49 【问题描述】:

我有一个用例,使用单独的连接表对具有@manytomany 关系的记录进行过滤和分页。 下面是关系和实体

   public class User 
        private Long userId;
        private String userName
        @OneToMany(mappedBy = "user")
        private List<UserRole> userRole;
    
public class Role 
    private Long roleId;
    private String roleName
    @OneToMany(mappedBy = "role")
    private List<UserRole> userRole;


public class UserRole
    private Long id;
    private Integer active
    @ManyToOne   
    @MapsId("userId")
    private User user;
    @ManyToOne   
    @MapsId("roleId")
    private Role role;

    @Repository
    public interface UserRoleRepository extends 
                       JpaRepository<UserRole, String>, 
                       JpaSpecificationExecutor<UserRole> 
    
     public class UserRoleSpecification implements Specification<UserRole> 
     
    
        private SearchCriteria criteria;
        
        public RuleEntitySpecification(SearchCriteria criteria ) 
            this.criteria = criteria;
        
    
        @Override
        public Predicate toPredicate(Root<UserRole> root, 
                               CriteriaQuery<?> query,
                               CriteriaBuilder criteriaBuilder) 
            
          if(criteria.getOperation().equalsIgnoreCase("eq")) 
             if(root.get(criteria.getKey()).getJavaType() == String.class) 
             
               return criteriaBuilder.like(root.get(criteria.getKey()), 
                                      "%" + criteria.getValue() + "%");
              else 
               return criteriaBuilder.equal(root.get(criteria.getKey()), 
                                            criteria.getValue());
             
           
           return null;
        
    
    
    public class SearchCriteria implements Serializable 
    
        private String key;
        private String operation;
        private Object value;
    
    UserRoleSpecificationBuilder specBuilder = new UserRoleSpecificationBuilder();
    
    specBuilder.with("active", "eq" , 1); // giving us proper result
    
    Specification<UserRole> spec = specBuilder.build();
    
    Pageable paging = PageRequest.of(0, 5, Sort.by("user.userId"));
    
    Page<UserRole> pagedResult = userRoleRepository.findAll(spec,paging);

但是,当我们尝试基于规则/用户表属性(如 userName/roleName specBuilder.with("user.userName", "eq" , "xyz");)进行过滤时,出现以下异常:

    org.springframework.dao.InvalidDataAccessApiUsageException: 
    Unable to locate Attribute  with the the given name 
    [user.userName] on this ManagedType

请建议是否有任何方法可以使用 UserRole Join Table 存储库和规范来实现过滤器

也需要分页,因此使用类型 UserRole JoinTable 的存储库。

【问题讨论】:

【参考方案1】:
    @Override
    public Predicate toPredicate(Root<UserRole> root,
                                 CriteriaQuery<?> query,
                                 CriteriaBuilder criteriaBuilder) 
      if (criteria.getOperation().equalsIgnoreCase("eq")) 
         String key = criteria.getKey();
         Path path;
         if (key.contains(".")) 
            String attributeName1 = key.split("\\.")[0];
            String attributeName2 = key.split("\\.")[1];
            path = root.get(attributeName1).get(attributeName2);
          else 
            path = root.get(key);
         
         if (path.getJavaType() == String.class) 
           return criteriaBuilder.like(path, "%" + criteria.getValue() + "%");
          else 
           return criteriaBuilder.equal(root.get(key), criteria.getValue());
         
      
      return null;
    

【讨论】:

非常感谢@Kavithakaran 这个解决方案。你太棒了.. :) .

以上是关于使用连接表存储库的@manytomany 中的 Spring 数据 jpa 规范和可分页的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate JPA 没有在 ManyToMany 关联上创建连接表

spring jpa ManyToMany 理解和使用

Hibernate中的ManyToMany映射引用错误(由api生成的表名)表Spring Boot

用jpa删除连接表中的行

在使用多个数据库时将记录插入表的 ManyToMany 字段

Django ManyToMany 字段上的自定义列名