我有一个MVC控制器,它将联系人列表作为JSON返回。在前端,我使用jquery datatables插件。前端有一个搜索字段来过滤实体列表。
我的实体:
@Entity
public class Contact implements Serializable {
protected final static Logger LOGGER = LoggerFactory.getLogger(Contact.class);
private static final long serialVersionUID = -3691953100225344828L;
@Id
@GeneratedValue(generator = "hibernate-uuid")
@Column(length = 36, unique = true)
private String id;
@Version
@JsonIgnore
private int version;
private String firstname;
private String lastname;
@ManyToOne
private Company company;
... GETTER/SETTER ...
}
和
@Entity
public class Company implements Serializable {
protected final static Logger LOGGER = LoggerFactory.getLogger(Company.class);
private static final long serialVersionUID = -7863930456400256944L;
@Id
@GeneratedValue(generator = "hibernate-uuid")
@Column(length = 36, unique = true)
private String id;
private String companyName;
private String companyName1;
private String companyName2;
... GETTER/SETTER ...
}
我在搜索字段使用服务器端处理,在服务器端使用规范。
public class ContactSpecifications {
public static Specification<Contact> contactFirstnameLike(final String needle) {
return new Specification<Contact>() {
@Override
public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(cb.lower(root.<String> get(Contact_.firstname)), needle != null ? needle.toLowerCase() : null);
}
};
}
public static Specification<Contact> contactLastnameLike(final String needle) {
return new Specification<Contact>() {
@Override
public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.like(cb.lower(root.<String> get(Contact_.lastname)), needle != null ? needle.toLowerCase() : null);
}
};
}
public static Specification<Contact> contactFullnameLike(final String needle) {
return new Specification<Contact>() {
@Override
public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
return cb.or(cb.like(cb.lower(root.<String> get(Contact_.lastname)), needle != null ? needle.toLowerCase() : null), cb.like(cb.lower(root.<String> get(Contact_.firstname)), needle != null ? needle.toLowerCase() : null));
}
};
}
public static Specification<Contact> contactCompanyCompanyNameLike(final String needle) {
return new Specification<Contact>() {
@Override
public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
final Path<Company> company = root.<Company> get(Contact_.company);
return cb.like(cb.lower(company.<String> get(Company_.companyName)), needle != null ? needle.toLowerCase() : null);
}
};
}
}
我的数据库查询
contactRepository.findAll(specifications, new PageRequest(0,100));
和规格
specifications = Specifications.where(ContactSpecifications.contactFullnameLike(needle)).or(ContactSpecifications.contactCompanyCompanyNameLike(needle));
needle是来自前端和掩码的搜索键,周围有%(例如“%asdf%”)
我的问题是,如果联系人没有公司,那么规格就无法按预期运行。
例如,我有3个联系人:
姓氏:Muster,名字:Max,公司:XY
答案 0 :(得分:6)
回答自己;)
在研究sql查询后,我找到了解决方案。我必须改写我的规格。在相关实体上,我必须添加一个左连接路径,以防止条件构建器自动使用交叉/内部连接。
内部联接仅返回已设置所有字段的实体。如果某个实体关系为null,则该实体从结果列表中删除。正常的内部联接行为。
所以...
正确的规范必须是这样的。
public static Specification<Contact> contactCompanyCompanyNameLike(final String needle) {
return new Specification<Contact>() {
@Override
public Predicate toPredicate(Root<Contact> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
final Join<Contact,Company> company = root.join(Contact_.company, JoinType.LEFT);
return cb.like(cb.lower(company.<String> get(Company_.companyName)), needle != null ? needle.toLowerCase() : null);
}
};
}
通过这些小修改,它现在开始正常工作。
亲切的问候Rizzi