2015-10-31 61 views
0

當前的項目,我使用過Spring數據JPA和春天開機,我發現這是非常convinence直到滿足這一要求最多的時間,我發現很難對付。 這是我採購實體和供應方實體和中間實體(BuyerSupplier),如果我想通過電話或名稱或兩個或所有搜索買家,我需要提供很多方法,象下面這樣:如何實現Spring數據JPA動態查詢和聯合查詢

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() 

顯然,上面的代碼是非常bad.And其實,我的業務邏輯比較複雜,同時,我想搜索買家屬於一個特殊的供應商,並可能具有特殊地位的買家。通訊像下面的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' 

任何人都可以給我一些示例代碼或文檔可以教我如何實現我的上述目標?

回答

0

IMO,你仍然需要寫這樣if(phone!=null&&name!=null)代碼。但你可以enscape的代碼,寫一次。 首先,你應該知道,支持well.Just下面粘貼我的代碼動態查詢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); 

OK,你可以使用拉姆達而不是匿名類所你可以enscape的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)