Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/spring-boot/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Spring boot JPA规范-可空字段上的多个OR条件和左连接_Spring Boot_Spring Data Jpa_Specifications_Hibernate Criteria_Criteria Api - Fatal编程技术网

Spring boot JPA规范-可空字段上的多个OR条件和左连接

Spring boot JPA规范-可空字段上的多个OR条件和左连接,spring-boot,spring-data-jpa,specifications,hibernate-criteria,criteria-api,Spring Boot,Spring Data Jpa,Specifications,Hibernate Criteria,Criteria Api,下面是我的模型课 顾客 public class Customer { @Id @GeneratedValue(strategy = GenerationType.AUTO) Long customerid; @NotNull String name; @NotNull @Column(name = "phone_no") @JsonProperty("phone_no") Str

下面是我的模型课

顾客

public class Customer {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long customerid;

    @NotNull
    String name;

    @NotNull
    @Column(name = "phone_no")
    @JsonProperty("phone_no")
    String phoneNo;

    String referer;

    @NotNull
    String email;

    @OneToOne (fetch = FetchType.LAZY)
    @JoinColumn(name = "agent_id", nullable = true)
    @JsonProperty(required = false)
    Agent agent;

    @OneToOne (fetch = FetchType.LAZY)
    @JoinColumn(name = "partner_id", nullable = true)
    @JsonProperty(required = false)
    Partner partner;
}
代理人

搭档

public class Partner extends UserDetails
{
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    Long partnerid;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="user_id",nullable=false)
    private User user;
}
映射超类

@MappedSuperclass
public class UserDetails 
{

    @NotNull
    @Column(name="name")
    String name;
    
    @NotNull
    @Column(name="mobileno")
    String mobileno;
    
    @NotNull
    @Column(name="email")
    String email;
业务逻辑-客户将填充“referer”字段,否则将是代理或合作伙伴。如果他与代理有关,我们将填充代理id,否则填充合作伙伴id

我想写一个规范,它将尝试根据这些可选字段进行过滤。搜索应该是

如果customer.referer匹配或agent.name匹配或partner.name匹配->返回记录

我必须对多个字符串执行此搜索。所以,我编写了可重用的方法来生成规范。下面是我的课程说明

public class CustomerSpecification {

    SpecificationsBuilder<Customer> specbldr = new SpecificationsBuilder<Customer>();

    public Specification<Customer> getSpecification(FilterDataListV2 filterDataList) throws Exception {
        
        Specification<Customer> finalSpec = null;
        List<String> globalSearch = SpecificationsBuilder.fetchValueFromFilterList(filterDataList, "globalSearch");

        if (globalSearch != null && globalSearch.size() > 0) {
            
            Specification<Customer> internalSpec1 = whereDirectFieldContains(Customer_.REFERER, globalSearch);
            Specification<Customer> internalSpec2 = whereChildFieldContains(Customer_.AGENT, Agent_.NAME, globalSearch);
            Specification<Customer> internalSpec3 = whereChildFieldContains(Customer_.PARTNER, Partner_.NAME, globalSearch);

            Specification<Customer> internalSpec = internalSpec1.or(internalSpec2).or(internalSpec3);

            finalSpec = specbldr.specAndCondition(finalSpec, internalSpec);
        }
        return finalSpec;
    }


    public Specification<Customer> whereDirectFieldContains(String key, List<String> names)
    {
        Specification<Customer> finalSpec = null;
        for (String name : names)
        {
            Specification<Customer> internalSpec = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> cb
                    .like(root.get(key), "%" + name + "%");
            finalSpec = specOrCondition(finalSpec, internalSpec);
        }
        return finalSpec;
    }

    public Specification<Customer> whereChildFieldContains(String childTable, String childFiledName, List<String> names)
    {
        Specification<Customer> finalSpec = null;
        for (String name : names)
        {
            Specification<Customer> internalSpec = (Root<Customer> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> cb
                    .like(root.get(childTable).get(childFiledName), "%" + name + "%");
            finalSpec = specOrCondition(finalSpec, internalSpec);
        }
        return finalSpec;
    }
    
    public Specification<Customer> specOrCondition(Specification<Customer> finalSpec, Specification<Customer> internalSpec)
    {
        if (finalSpec == null)
            return internalSpec;
        else
            return finalSpec.or(internalSpec);
    }

    public Specification<Customer> specAndCondition(Specification<Customer> finalSpec, Specification<Customer> internalSpec)
    {
        if (finalSpec == null)
            return internalSpec;
        else
            return finalSpec.and(internalSpec);
    }
}
生成的SQL

select
            customer0_.customerid as customer1_3_,
            customer0_.agent_id as agent_id6_3_,
            customer0_.email as email2_3_,
            customer0_.name as name3_3_,
            customer0_.partner_id as partner_7_3_,
            customer0_.phone_no as phone_no4_3_,
            customer0_.referer as referer5_3_ 
        from
            customer customer0_ cross 
        join
            agent agent1_ cross 
        join
            partner partner3_ 
        where
            customer0_.agent_id=agent1_.agentid 
            and customer0_.partner_id=partner3_.partnerid -- This AND condition should not be there
            and (
                customer0_.referer like ? 
                or customer0_.referer like ? 
                or agent1_.name like ? 
                or agent1_.name like ? 
                or partner3_.name like ? 
                or partner3_.name like ?
            ) 
        order by
            customer0_.customerid

有人能帮我解决哪里出了问题吗

使用JoinType.LEFT解决了这个问题。在下面创建了一个可重用的通用方法,用于左连接实体,并且有效

public Specification<T> whereDirectFieldLeftJoinContains(String table, String field, List<String> globalSearch) {
        Specification<T> finalSpec = null;
        for (String name : globalSearch)
        {
            Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> cb
                    .like(root.join(table, JoinType.LEFT).get(field), "%" + name + "%");
            finalSpec = specOrCondition(finalSpec, internalSpec);
        }
        return finalSpec;
    }
公共规范,其中DirectFieldLeftJoinContains(字符串表、字符串字段、列表全局搜索){
规范finalSpec=null;
for(字符串名称:globalSearch)
{
规范internalSpec=(根目录,CriteriaQuery查询,CriteriaBuilder cb)->cb
.like(root.join(table,JoinType.LEFT).get(field),“%”+name+“%”;
最终规范=规范条件(最终规范,内部规范);
}
返回最终规格;
}
select
            customer0_.customerid as customer1_3_,
            customer0_.agent_id as agent_id6_3_,
            customer0_.email as email2_3_,
            customer0_.name as name3_3_,
            customer0_.partner_id as partner_7_3_,
            customer0_.phone_no as phone_no4_3_,
            customer0_.referer as referer5_3_ 
        from
            customer customer0_ cross 
        join
            agent agent1_ cross 
        join
            partner partner3_ 
        where
            customer0_.agent_id=agent1_.agentid 
            and customer0_.partner_id=partner3_.partnerid -- This AND condition should not be there
            and (
                customer0_.referer like ? 
                or customer0_.referer like ? 
                or agent1_.name like ? 
                or agent1_.name like ? 
                or partner3_.name like ? 
                or partner3_.name like ?
            ) 
        order by
            customer0_.customerid
public Specification<T> whereDirectFieldLeftJoinContains(String table, String field, List<String> globalSearch) {
        Specification<T> finalSpec = null;
        for (String name : globalSearch)
        {
            Specification<T> internalSpec = (Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> cb
                    .like(root.join(table, JoinType.LEFT).get(field), "%" + name + "%");
            finalSpec = specOrCondition(finalSpec, internalSpec);
        }
        return finalSpec;
    }