如何实现Spring Data Jpa动态查询和联合查询

时间:2015-10-31 03:26:08

标签: spring-data-jpa

当前项目我使用的是Spring数据jpa和spring boot,大多数时候我发现它非常有意义,直到满足这个要求,我发现很难处理。 那就是我有买方实体和供应商实体以及中间实体(买方供应商),如果我想通过电话或名称或两者或全部搜索买方,我必须提供许多方法,如下所示:

if(phone!=null&&name!=null)
    List<Buyer> findByPhoneAndName(phone,name)
else if(phone!=null)
    List<Buyer> findByPhone(phone)
else if(name!=null)
    List<Buyer> findByName(name)
else
    List<Buyer> findAll()

显然,上面的代码非常糟糕。实际上,我的业务逻辑更复杂,同时我想搜索买家属于特殊供应商,也许是特殊状态买家。对应的sql如下:

select b.* from buyer b, buyer_supplier bs
where b.id = bs.buyer_id
and bs.supplier_id = 1
and bs.stauts = 'Activated'
and b.name like '%foo%'
and b.phone like '%123%'

我也想构建动态sql,如下所示:

select b.* from buyer b, buyer_supplier bs
where b.id = bs.buyer_id
if(name != null)
    and b.name like '%foo%'
if(phone!=null)
    and b.phone like '%123%'
if(supplierId>0)
    and b.supplier_id = 1
if(status!=null)
    and bs.stauts = 'Activated'

任何人都可以给我一些代码示例或文件可以教我如何实现我的上述目标吗?

1 个答案:

答案 0 :(得分:0)

IMO,您仍然需要编写像if(phone!=null&&name!=null)这样的代码。但是您可以插入代码并编写一次。 首先,您应该知道支持动态查询的Specification<T>。只需在下面粘贴我的代码。

Specification<Goods> spec = new Specification<Goods>() {
    @Override
    public Predicate toPredicate(Root<Goods> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
         Predicate predicate = cb.conjunction();
                if (goodsSearch.getGoodsClassId() != -1) {
                    predicate = cb.and(predicate, cb.equal(root.get("goodsClassId"), goodsSearch.getGoodsClassId()));
                }

                return query.where(predicate).getRestriction();
            }
        };
return goodsDao.findAll(spec, pageable);

好的,您可以使用lambda而不是匿名类。然后您可以查看Specification<T>,将if(phone!=null&&name!=null)之类的代码放入其中。 示例代码:

public Specification<T> term(String fieldName, Operator operator, Object value) {
        return new Specification<T>() {
            @Override
            public Predicate toPredicate(Root<T> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder builder) {
                if (value == null) {
                    return null;
                }
                Path expression = null;
                // if a.b, then use join
                if (fieldName.contains(".")) {
                    String[] names = StringUtils.split(fieldName, ".");
                    expression = root.get(names[0]);
                    for (int i = 1; i < names.length; i++) {
                        expression = expression.get(names[i]);
                    }
                } else {
                    expression = root.get(fieldName);
                }
                // the different operation
                switch (operator) {
                    case EQ:
                        return builder.equal(expression, value);
                    case NE:
                        return builder.notEqual(expression, value);
                    case LT:
                        return builder.lessThan(expression, (Comparable) value);
                    case GT:
                        return builder.greaterThan(expression, (Comparable) value);
                    case LIKE:
                        return builder.like((Expression<String>) expression, "%" + value + "%");
                    case LTE:
                        return builder.lessThanOrEqualTo(expression, (Comparable) value);
                    case GTE:
                        return builder.greaterThanOrEqualTo(expression, (Comparable) value);
                    case BT:
                        List<Object> paramList = (List<Object>) value;
                        if (paramList.size() == 2) {
                            return builder.between(expression, (Comparable) paramList.get(0), (Comparable) paramList.get(1));
                        }
                    case IN:
                        return builder.in(expression).value(value);
                    default:
                        return null;
                }
            }
        };
    }

我没有在其中编写示例代码if(phone!=null&&name!=null)

相关问题