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;
}