我在SpringData中使用QueryDSL。
我有表说,Employee
我创建了实体类,EmployeeEntity
我写了以下服务方法
public EmployeeEntity getEmployees(String firstName, String lastName)
{
QEmployeeEntity employee = QEmployeeEntity.employeeEntity;
BooleanExpression query = null;
if(firstName != null)
{
query = employee.firstName.eq(firstName);
}
if(lastName != null)
{
query = query.and(employee.lastName.eq(lastName)); // NPException if firstName is null as query will be NULL
}
return empployeeDAO.findAll(query);
}
如上所述,我评论了NPException
。如何使用Spring数据将 QueryDSL 用于 QueryDSL 中的可选参数?
谢谢:)
答案 0 :(得分:29)
BooleanBuilder
可以用作布尔表达式的动态构建器:
public EmployeeEntity getEmployees(String firstName, String lastName) {
QEmployeeEntity employee = QEmployeeEntity.employeeEntity;
BooleanBuilder where = new BooleanBuilder();
if (firstName != null) {
where.and(employee.firstName.eq(firstName));
}
if (lastName != null) {
where.and(employee.lastName.eq(lastName));
}
return empployeeDAO.findAll(where);
}
答案 1 :(得分:8)
BooleanBuilder很好。您也可以将其包装并添加"可选"方法,以避免if条件:
例如,对于"和"你可以写:(使用Java 8 lambdas)
public class WhereClauseBuilder implements Predicate, Cloneable
{
private BooleanBuilder delegate;
public WhereClauseBuilder()
{
this.delegate = new BooleanBuilder();
}
public WhereClauseBuilder(Predicate pPredicate)
{
this.delegate = new BooleanBuilder(pPredicate);
}
public WhereClauseBuilder and(Predicate right)
{
return new WhereClauseBuilder(delegate.and(right));
}
public <V> WhereClauseBuilder optionalAnd(@Nullable V pValue, LazyBooleanExpression pBooleanExpression)
{
return applyIfNotNull(pValue, this::and, pBooleanExpression);
}
private <V> WhereClauseBuilder applyIfNotNull(@Nullable V pValue, Function<Predicate, WhereClauseBuilder> pFunction, LazyBooleanExpression pBooleanExpression)
{
if (pValue != null)
{
return new WhereClauseBuilder(pFunction.apply(pBooleanExpression.get()));
}
return this;
}
}
@FunctionalInterface
public interface LazyBooleanExpression
{
BooleanExpression get();
}
然后使用会更清洁:
public EmployeeEntity getEmployees(String firstName, String lastName) {
QEmployeeEntity employee = QEmployeeEntity.employeeEntity;
return empployeeDAO.findAll
(
new WhereClauseBuilder()
.optionalAnd(firstName, () -> employee.firstName.eq(firstName))
.optionalAnd(lastName, () -> employee.lastName.eq(lastName))
);
}
也可以使用jdk的Optional类
答案 2 :(得分:3)
实际上这是Java 101:检查null
并初始化查询而不是连接谓词。所以像这样的辅助方法可以解决这个问题:
private BooleanExpression createOrAnd(BooleanExpression left, BooleanExpression right) {
return left == null ? right : left.and(right);
}
然后你就可以做到:
BooleanExpression query = null;
if (firstName != null) {
query = createOrAnd(query, employee.firstName.eq(firstName));
}
if (lastName != null) {
query = createOrAnd(query, employee.lastName.eq(lastName));
}
…
请注意,我甚至在第一个子句中使用createOrAnd(…)
只是为了保持一致性,并且如果您决定在firstName
之前添加新子句,则不必调整该代码。< / p>
答案 3 :(得分:1)
我遇到了同样的问题,下面是使用for /R "C:\extract" %%I in ("*.7z_encrpt") do ("C:\Program Files\7-Zip\7z.exe" X -y -o"%%~dpI" "%%~fI")
for /R "C:\extract" %%I in ("*.zip_encrpt") do ("C:\Program Files\7-Zip\7z.exe" X -y -o"%%~dpI" "%%~fI")
的{{3}}的Timo Westkämper
的另一个版本。
Optional
答案 4 :(得分:0)
如果您检查null
的QueryDSL实现:
public BooleanExpression and(@Nullable Predicate right) {
right = (Predicate) ExpressionUtils.extract(right);
if (right != null) {
return BooleanOperation.create(Ops.AND, mixin, right);
} else {
return this;
}
}
这应该是你想要的。
答案 5 :(得分:0)
根据你的需要我会做到这一点
public List<EmployeeEntity> getEmployees(Optional<String> firstName, Optional<String> lastName)
{
BooleanExpression queryPredicate = QEmployeeEntity.employeeEntity.firstName.containsIgnoreCase(firstName.orElse("")).and(QEmployeeEntity.employeeEntity.lastName.containsIgnoreCase(lastName.orElse("")));
return empployeeDAO.findAll(queryPredicate);
}
首先,您应该返回List
EmployeeEntity
。其次,使用可选项比检查其null
更好,并且您可以传递从可选的Optional
获得的Java 8 RequestParam
值,如下所示:
@RequestMapping(value = "/query", method = RequestMethod.GET)
public ModelAndView queryEmployee(@RequestParam(value = "firstName", required = false) Optional<String> firstName, @RequestParam(value = "lastName", required = false) Optional<String> lastName)
{
List<EmployeeEntity> result = getEmployees(firstName, lastName);
....
}
一个非常重要的事情是在谓词中使用containsIgnoreCase
函数:它比典型的like
更好,因为它不区分大小写。
在我看来,你应该使用这样的方法:
@Controller
class UserController {
@Autowired UserRepository repository;
@RequestMapping(value = "/", method = RequestMethod.GET)
String index(Model model, @QuerydslPredicate(root = User.class) Predicate predicate,
Pageable pageable, @RequestParam MultiValueMap<String, String> parameters) {
model.addAttribute("users", repository.findAll(predicate, pageable));
return "index";
}
}
查看here。
答案 6 :(得分:0)
这是处理可选参数的一种非常简单的方法,我在我的项目中使用它:
public List<ResultEntity> findByOptionalsParams(String param1, Integer param2) {
QResultEntity qResultEntity = QResultEntity.resultEntity;
final JPQLQuery<ResultEntity> query = from(qResultEntity);
if (!StringUtils.isEmpty(param1)) {
query.where(qResultEntity.field1.like(Expressions.asString("%").concat(param1).concat("%")));
}
if (param2 != null) {
query.where(qResultEntity.field2.eq(param2));
}
return query.fetch();
}
答案 7 :(得分:0)
还有一种使用Optional
而不使用BooleanBuilder
的方法,尽管结果查询可能有点冗长:
public EmployeeEntity getEmployees(String firstName, String lastName) {
QEmployeeEntity employee = QEmployeeEntity.employeeEntity;
BooleanExpression where = ofNullable(firstName).map(employee.firstName::eq).orElse(Expressions.TRUE)
.and(ofNullable(lastName).map(employee.lastName::eq).orElse(Expressions.TRUE));
return empployeeDAO.findAll(where);
}
采用这个想法并添加一个辅助函数可以提高可读性:
public EmployeeEntity getEmployees(String firstName, String lastName) {
QEmployeeEntity employee = QEmployeeEntity.employeeEntity;
BooleanExpression where = optionalExpression(firstName, employee.firstName::eq)
.and(optionalExpression(lastName, employee.lastName::eq));
return empployeeDAO.findAll(where);
}
public static <T> BooleanExpression optionalExpression(T arg, Function<T, BooleanExpression> expressionFunction) {
if (arg == null) {
return Expressions.TRUE;
}
return expressionFunction.apply(arg);
}
答案 8 :(得分:0)
对于任何想要基于动态请求参数映射而非特定参数构建谓词的人,都可以使用以下简单格式,
public List<User> searchUser(Map<String, Optional<String>> requestParams ){
QUser qUser = Quser.qUser;
BooleanBuilder builder = new BooleanBuilder();
requestParams.forEach( (String key, String value) -> {
if(!value.isEmpty()) {
StringPath column = Expressions.stringPath(qUser, key);
builder.and(column.eq(value));
}
});
}
这是我的控制器
@RequestMapping(value = "", method = RequestMethod.GET)
public ResponseEntity<List<User>> searchUser(
@RequestParam() Map<String, Optional<String>> requestParams) {
List<User> userList = userService.searchUser(requestParams);
if(userList!=null)
return new ResponseEntity<>(userList, HttpStatus.OK);
else
return new ResponseEntity<>(userList, HttpStatus.INTERNAL_SERVER_ERROR);
}