JPA+QueryDSL
工作需要,接觸到了QueryDSL,總結(jié)使用方法,參考了幾個(gè)大佬的文章,對(duì)我?guī)椭艽?參考文章1,參考文章2,參考文章3,參考文章4感謝大佬們!!!
使用場(chǎng)景
JPA,JDO,SQL,Java,Collections,RDF,Lucene,Hibernate Search。
QueryDSL官網(wǎng):http://querydsl.com/static/querydsl/4.1.3/reference/html_single/
一些概念
在 JPA 規(guī)范中, EntityManager 是完成持久化操作的核心對(duì)象。實(shí)體作為普通 Java 對(duì)象,只有在調(diào)用 EntityManager 將其持久化后才會(huì)變成持久化對(duì)象。
EntityManager 對(duì)象在一組實(shí)體類與底層數(shù)據(jù)源之間進(jìn)行 O/R 映射的管理。它可以用來(lái)管理和更新 Entity Bean, 根椐主鍵查找 Entity Bean, 還可以通過(guò)JPQL語(yǔ)句查詢實(shí)體。
Persistence context是由一組受托管的實(shí)體對(duì)象實(shí)例所構(gòu)成的集合。它受entity manager 的管理。Entity manager追蹤persistence context中所有對(duì)象的修改和更新情況,并根據(jù)指定的flush模式(本章稍后會(huì)做討論)將這些修改保存到數(shù)據(jù)庫(kù)中。一旦persistence context被關(guān)閉,所有實(shí)體對(duì)象實(shí)例都會(huì)脫離EntityManager而成為非托管對(duì)象。對(duì)象一旦從persistence context中脫離,就不再受entity manager管理了,任何對(duì)此對(duì)象的狀態(tài)變更也將不會(huì)被同步到數(shù)據(jù)庫(kù)。
使用方法
pom文件的導(dǎo)入
<!-- queryDSL --><dependency><groupId>com.querydsl</groupId><artifactId>querydsl-jpa</artifactId></dependency><!-- queryDSL --><dependency><groupId>com.querydsl</groupId><artifactId>querydsl-apt</artifactId><scope>provided</scope></dependency><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin><!--因?yàn)槭穷愋桶踩?#xff0c;所以還需要加上Maven APT plugin,使用 APT 自動(dòng)生成一些類:--><plugin><groupId>com.mysema.maven</groupId><artifactId>apt-maven-plugin</artifactId><version>1.1.3</version><executions><execution><phase>generate-sources</phase><goals><goal>process</goal></goals><configuration><outputDirectory>target/generated-sources</outputDirectory><processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor></configuration></execution></executions></plugin></plugins> </build>下面是兩個(gè)大佬的文章里給出的例子,根據(jù)例子學(xué)習(xí)非常快,再次感謝大佬們!!!
例1
IDEA 的Maven面板,項(xiàng)目生命周期里重新編譯項(xiàng)目,會(huì)自動(dòng)生成Q實(shí)體類
例2
一. 實(shí)體類
二. 單表動(dòng)態(tài)分頁(yè)查詢
Spring Data JPA中提供了QueryDslPredicateExecutor接口,用于支持QueryDSL的查詢操作
public interface tCityRepository extends JpaRepository<TCity, Integer>, QueryDslPredicateExecutor<TCity> {}這樣的話單表動(dòng)態(tài)查詢就可以參考如下代碼:
//查找出Id小于3,并且名稱帶有`shanghai`的記錄. //動(dòng)態(tài)條件 QTCity qtCity = QTCity.tCity; //SDL實(shí)體類 //該P(yáng)redicate為querydsl下的類,支持嵌套組裝復(fù)雜查詢條件 Predicate predicate = qtCity.id.longValue().lt(3).and(qtCity.name.like("shanghai")); //分頁(yè)排序 Sort sort = new Sort(new Sort.Order(Sort.Direction.ASC,"id")); PageRequest pageRequest = new PageRequest(0,10,sort); //查找結(jié)果 Page<TCity> tCityPage = tCityRepository.findAll(predicate,pageRequest);三. 多表動(dòng)態(tài)查詢
QueryDSL對(duì)多表查詢提供了一個(gè)很好地封裝,看下面代碼:
/** * 關(guān)聯(lián)查詢示例,查詢出城市和對(duì)應(yīng)的旅店 * @param predicate 查詢條件 * @return 查詢實(shí)體 */ @Override public List<Tuple> findCityAndHotel(Predicate predicate) { JPAQueryFactory queryFactory = new JPAQueryFactory(em); JPAQuery<Tuple> jpaQuery = queryFactory.select(QTCity.tCity,QTHotel.tHotel) .from(QTCity.tCity) .leftJoin(QTHotel.tHotel) .on(QTHotel.tHotel.city.longValue().eq(QTCity.tCity.id.longValue())); //添加查詢條件 jpaQuery.where(predicate); //拿到結(jié)果 return jpaQuery.fetch(); }城市表左連接旅店表,當(dāng)該旅店屬于這個(gè)城市時(shí)查詢出兩者的詳細(xì)字段,存放到一個(gè)Tuple的多元組中.相比原生sql,簡(jiǎn)單清晰了很多.
那么該怎么調(diào)用這個(gè)方法呢?
這樣做的話避免了返回Object[]數(shù)組,下面是自動(dòng)生成的sql語(yǔ)句:
select tcity0_.id as id1_0_0_, thotel1_.id as id1_1_1_, tcity0_.country as country2_0_0_, tcity0_.map as map3_0_0_, tcity0_.name as name4_0_0_, tcity0_.state as state5_0_0_, thotel1_.address as address2_1_1_, thotel1_.city as city3_1_1_, thotel1_.name as name4_1_1_ from t_city tcity0_ left outer join t_hotel thotel1_ on ( cast(thotel1_.city as signed)=cast(tcity0_.id as signed) ) where tcity0_.name like ? escape '!'四 多表動(dòng)態(tài)分頁(yè)查詢
分頁(yè)查詢對(duì)于queryDSL無(wú)論什么樣的sql只需要寫(xiě)一遍,會(huì)自動(dòng)轉(zhuǎn)換為相應(yīng)的count查詢,下面代碼是對(duì)上面的查詢加上分頁(yè)功能:
@Override public QueryResults<Tuple> findCityAndHotelPage(Predicate predicate,Pageable pageable) { JPAQueryFactory queryFactory = new JPAQueryFactory(em); JPAQuery<Tuple> jpaQuery = queryFactory.select(QTCity.tCity.id,QTHotel.tHotel) .from(QTCity.tCity) .leftJoin(QTHotel.tHotel) .on(QTHotel.tHotel.city.longValue().eq(QTCity.tCity.id.longValue())) .where(predicate) .offset(pageable.getOffset()) .limit(pageable.getPageSize()); //拿到分頁(yè)結(jié)果 return jpaQuery.fetchResults(); }和上面不同之處在于這里使用了offset和limit限制查詢結(jié)果,并且返回一個(gè)QueryResults。該類會(huì)自動(dòng)實(shí)現(xiàn)count查詢和結(jié)果查詢,并進(jìn)行封裝。
調(diào)用形式如下:
生成的原生count查詢sql,當(dāng)該count查詢結(jié)果為0的話,則直接返回,并不會(huì)再進(jìn)行具體數(shù)據(jù)查詢:
select count(tcity0_.id) as col_0_0_ from t_city tcity0_ left outer join t_hotel thotel1_ on ( cast(thotel1_.city as signed)=cast(tcity0_.id as signed) ) where tcity0_.name like ? escape '!'生成的原生查詢sql:
select tcity0_.id as id1_0_0_, thotel1_.id as id1_1_1_, tcity0_.country as country2_0_0_, tcity0_.map as map3_0_0_, tcity0_.name as name4_0_0_, tcity0_.state as state5_0_0_, thotel1_.address as address2_1_1_, thotel1_.city as city3_1_1_, thotel1_.name as name4_1_1_ from t_city tcity0_ left outer join t_hotel thotel1_ on ( cast(thotel1_.city as signed)=cast(tcity0_.id as signed) ) where tcity0_.name like ? escape '!' limit ?查看打印,可以發(fā)現(xiàn)對(duì)應(yīng)的city也都是同一個(gè)對(duì)象,hotel是不同的對(duì)象。
總結(jié)
以上是生活随笔為你收集整理的JPA+QueryDSL的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: Android下常见的内存泄露 经典
- 下一篇: Winform datagridview