欢迎访问昆山宝鼎软件有限公司网站! 设为首页 | 网站地图 | XML | RSS订阅 | 宝鼎邮箱 | 宝鼎售后问题提交 | 后台管理


新闻资讯

MENU

软件开发知识

namedParameters); QueryTranslator trans 昆山软件定制开发 lator = tra

点击: 次  来源:宝鼎软件 时间:2017-06-01

原文出处: liweisnake

最近利用了spring data jpa来完成数据会见层的实现。感受较量强大,也较量巨大,中间尚有不少限制。

话说数据库sql的应用有点像打怪进级,一点一点不绝增加难度。

1. 对付一般应用中种种简朴的增删查改,spring data提供了按照名字直接查询的署理要领,啥都不需要做,独一需要编写接口,定名要领,这部门实在是太利便了,并且简朴查询办理了差不多80%的问题。这部门相对简朴,不再赘述,参考用法大全部门。

2. 对付巨大但又相对牢靠的查询,可以利用JPQL和Native Sql,即@Query直接写JPQL语句的方法。这部门也不难,简朴给个例子,需要留意的是返回功效假如是多个值而且返回多组,那应该以Object[][]暗示

@Query(value = "SELECT su.id, su.name_CN, avg(s.rate), count(b.id), count(concat(b.key, '@', s.admin)) "  
            + "FROM  " + CommonConstants.SCHEMA_PREFIX + "Submarket su,  " + CommonConstants.SCHEMA_PREFIX + "Building b,  " + CommonConstants.SCHEMA_PREFIX + "Space s,  " + CommonConstants.SCHEMA_PREFIX + "Market m,  " + CommonConstants.SCHEMA_PREFIX + "City c "  
            + "where b.submarket_id = su.id and s.building_id = b.id and su.market_id = m.id and m.city_id = c.id and c.country_id = ?1 group by su.id", nativeQuery=true)  
    Object[][] findAreaInfoByCountryId(int parentId);

3. 对付巨大且动态的查询,利用Criteria。对付criteria的用法,那就有相当多的内容了。需要利用到criteria的场景凡是是界面上有各类过滤和条件选项。

Criteria由于需要利用类的方法将整个巨大sql语句组织起来,因此有不少类,我们先来领略下这些类的寄义。

3.1大大都环境下,搜索返回的功效是一个数据库中的实体工具,对付这种环境,实际上可以直接利用spring data jpa提供的toPredicate要领,软件开发,该要领界说如下

public interface Specification<T> {  

    Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder cb);  
}

实际利用时只需要把预界说好的Repository工具担任JpaSpecificationExecutor工具即可

@Repository    
public interface CityDao extends JpaSpecificationExecutor<City>{    
}

真正挪用时只需要通报如下回调要领,spring会自动帮你完身分页

Page<City> page = cityDao.findAll(new Specification<City>() {    
            @Override    
            public Predicate toPredicate(Root<City> root, CriteriaQuery<?> query, CriteriaBuilder cb) {    
                root = query.from(City.class);    
                Path<String> nameExp = root.get("name");    
                return cb.like(nameExp, "%北京%");    
            }    

        }, new PageRequest(1, 5, new Sort(Direction.DESC, new String[] { "id" })));

对付这种环境,固然动态查询较量巨大,可是要名誉是个中相当简朴的范例了。

3.2 我们来看boss进级难度今后的环境。如果此时你的查询中不是一个简朴实体范例,而是一个巨大的聚合工具,有一堆聚合查询,有一堆a工具的属性,一堆b工具的属性。大概你还试图用toPredicate要领继承,但实际上Page只答允你通报已界说好的数据库中的实体工具,因为其root中界说的泛型实际上限制了后续的行为,好比想在root上join,假如root不是一个数据库实体则编译就报错了。别的由此激发的query.multiselect自界说查询功效无效,因为功效默认就是你界说好的谁人实体。这时候的办理步伐就是自界说dao实现类。首先,界说一个自界说实现接口

@NoRepositoryBean  
public interface SearchJpaRepositoryCustom {  

    public Page<Tuple> searchListing(final ListingSearchContext searchContext, Pageable pageable);  

}

其次,dao接口得担任该自界说接口

public interface BuildingRepository extends PagingAndSortingRepository<Building, Integer>, SearchJpaRepositoryCustom

然后,真正的dao模子实现类如下,需要留意,自界说的实现类必需实现自界说接口,而且,名字是BuildingRepository+impl,留意这里踩过坑

public class BuildingRepositoryImpl extends PagableRepository implements SearchJpaRepositoryCustom {  

    @PersistenceContext  
    private EntityManager em;  

    private Join<Space, ?> getSearchExpression(final CriteriaBuilder cb, final ListingSearchContext searchContext,  
            final Root<Space> root, final Predicate predicate) {  
        List<Expression<Boolean>> expressions = predicate.getExpressions();  
        // 只搜索版本为0的(即当前版本)  
        expressions.add(cb.equal(root.<String> get("ver"), 0));  
        if (searchContext.getSpaceId() > 0) {  
            expressions.add(cb.equal(root.<Integer> get("id"), searchContext.getSpaceId())); // id  
        }  
        if (null != searchContext.getMinRate()) {  
            expressions.add(cb.greaterThanOrEqualTo(root.<BigDecimal> get("rate"), searchContext.getMinRate())); // 价值  
        }  
        if (null != searchContext.getMaxRate()) {  
            expressions.add(cb.lessThanOrEqualTo(root.<BigDecimal> get("rate"), searchContext.getMaxRate())); // 价值  
        }  
        if (null != searchContext.getLCD()) {  
            expressions.add(cb.lessThanOrEqualTo(root.<Date> get("dateAvailable"), searchContext.getLCD())); // 可用日期  
        }  
        // spaceTypeId  
        if (searchContext.getSpaceTypeId() > 0) {  
            expressions.add(cb.equal(root.<String> get("spaceType").get("id"), searchContext.getSpaceTypeId()));  
        }  
        // buildingGrade&submarket  
        Join<Space, ?> buildingJoin = root.join(root.getModel().getSingularAttribute("building"), JoinType.INNER);  
        if (searchContext.getBuildingGradeId() > 0) {  
            expressions.add(cb.equal(buildingJoin.get("buildingGrade").get("id"), searchContext.getBuildingGradeId()));  
        }  
        if (searchContext.getSubmarketId() > 0) {  
            expressions.add(cb.equal(buildingJoin.get("submarket").get("id"), searchContext.getSubmarketId()));  
        }  
        if (StringUtils.isNotEmpty(searchContext.getKeyword())) {  
            Predicate like1 = cb.like(buildingJoin.<String> get("buildingNameCn"),  
                    "%" + searchContext.getKeyword() + "%");  
            Predicate like2 = cb.like(buildingJoin.<String> get("addressCn"), "%" + searchContext.getKeyword() + "%");  
            expressions.add(cb.or(like1, like2)); // 要害字  
        }  
        return buildingJoin;  
    }  

    @Override  
    public Page<Tuple> searchListing(final ListingSearchContext searchContext, Pageable pageable) {  
        final CriteriaBuilder cb = em.getCriteriaBuilder();  
        final CriteriaQuery<Tuple> query = cb.createTupleQuery();  
        final Root<Space> root = query.from(Space.class);  

        Predicate predicate = cb.conjunction();  

        Join<Space, ?> buildingJoin = getSearchExpression(cb, searchContext, root, predicate);  

        Join<Space, ?> spaceTypeJoin = root.join(root.getModel().getSingularAttribute("spaceType"), JoinType.INNER);  

        Join<Space, ?> contiguousJoin = root.join(root.getModel().getSingularAttribute("contiguous"), JoinType.INNER);  

        Join<Building, ?> assetJoin = buildingJoin.join("asset", JoinType.INNER);  

        Join<BuildingGrade, ?> buildingGradeJoin = buildingJoin.join("buildingGrade", JoinType.INNER);  

        SetJoin<Asset, ?> mediaJoin = assetJoin.joinSet("medias");  

        mediaJoin.on(cb.and(cb.equal(mediaJoin.get("type"), "photo"), cb.equal(mediaJoin.get("subtype"), "main")));  

        Expression<BigDecimal> maxConExp = cb.max(contiguousJoin.<BigDecimal> get("maxContiguous"));  
        Expression<BigDecimal> totalConExp = cb.sum(root.<BigDecimal> get("size"));  
        query.multiselect(cb.count(root.<Integer> get("id")), root.<Integer> get("userByAdmin").get("id"), totalConExp,  
                maxConExp, cb.min(root.<BigDecimal> get("minDivisible")), root.<Integer> get("building"),  
                cb.max(root.<Integer> get("stage")), cb.min(root.<Integer> get("lcd")),  
                cb.min(root.<Integer> get("led")), cb.min(root.<Integer> get("floor")),  
                cb.max(root.<Integer> get("floor")), mediaJoin.get("path"), spaceTypeJoin.get("nameEn"),  
                buildingGradeJoin.get("nameEn"));  

        query.where(predicate);  
        query.orderBy(cb.desc(root.get("gmtCreate").as(Date.class)));  
        query.groupBy(root.<Integer> get("building").get("id"), root.<String> get("userByAdmin").get("id"));  

        Predicate minExp = null;  
        Predicate maxExp = null;  
        Predicate minMaxResultExp = null;  
        if (null != searchContext.getMinSize()) {  
            minExp = cb.greaterThanOrEqualTo(cb.min(root.<BigDecimal> get("minDivisible")), searchContext.getMinSize()); // 最小面积  
            minMaxResultExp = minExp;  
        }  
        if (null != searchContext.getMaxSize()) {  
            maxExp = cb.lessThanOrEqualTo(searchContext.isContiguous() ? maxConExp : totalConExp,  
                    searchContext.getMaxSize()); // 最大面积  
            minMaxResultExp = maxExp;  
        }  
        if (null != searchContext.getMinSize() && null != searchContext.getMaxSize()) {  
            minMaxResultExp = cb.or(minExp, maxExp);  
        }  
        if (null != minMaxResultExp) {  
            query.having(minMaxResultExp);  
        }  
        TypedQuery<Tuple> pagableQuery = em.createQuery(query);  
        return pageable == null ? new PageImpl<Tuple>(pagableQuery.getResultList())  
                : readPage(pagableQuery, pageable);  
    }  

}