最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

解析JPA的視圖查詢問(wèn)題

 更新時(shí)間:2013年12月05日 08:55:28   作者:  
這篇文章主要是對(duì)JPA的視圖查詢問(wèn)題進(jìn)行了詳細(xì)的分析介紹,需要的朋友可以過(guò)來(lái)參考下,希望對(duì)大家有所幫助

昨天晚上遇到一個(gè)需求,每天早上要生成一份報(bào)告給各個(gè)部門的Leader。實(shí)現(xiàn)方式基本上確定為HTML格式的電子郵件。但是數(shù)據(jù)方面犯了難。原因在于數(shù)據(jù)庫(kù)中存儲(chǔ)的數(shù)據(jù)是跨表的,而且還要做count統(tǒng)計(jì),這樣得到的結(jié)果就不是原生的MySQL表,我用的又是JPA技術(shù)。我們知道,使用JPA第一步就是映射實(shí)體,每一張表就至少對(duì)應(yīng)一個(gè)實(shí)體(力求嚴(yán)謹(jǐn),因?yàn)槁?lián)合主鍵時(shí)一張表會(huì)對(duì)應(yīng)兩個(gè)對(duì)象)??墒菍?duì)于靈活的查詢尤其是連接查詢,并不存在一個(gè)真正的表與其對(duì)應(yīng),怎么樣才能解決呢?來(lái),我們來(lái)舉個(gè)“栗子”

假設(shè)我們有兩張表,一張學(xué)院表,一張學(xué)生表。學(xué)院表里存著學(xué)院ID和學(xué)院名稱,學(xué)生表里存著學(xué)生的基本信息,包括學(xué)號(hào)、學(xué)院ID和學(xué)生姓名(其它較復(fù)雜的屬性我們不看了),正如下面的建表語(yǔ)句所示:

復(fù)制代碼 代碼如下:

-- ----------------------------
-- Table structure for `depts`
-- ----------------------------
DROP TABLE IF EXISTS `depts`;
CREATE TABLE `depts` (
  `deptId` int(11) unsigned NOT NULL AUTO_INCREMENT COMMENT '學(xué)院ID',
  `deptName` varchar(50) NOT NULL COMMENT '學(xué)院名稱',
  PRIMARY KEY (`deptId`)
) ENGINE=InnoDB AUTO_INCREMENT=14 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of depts
-- ----------------------------
INSERT INTO `depts` VALUES ('1', '哲學(xué)院');
INSERT INTO `depts` VALUES ('2', '經(jīng)濟(jì)學(xué)院');
INSERT INTO `depts` VALUES ('3', '法學(xué)院');
INSERT INTO `depts` VALUES ('4', '教育學(xué)院');
INSERT INTO `depts` VALUES ('5', '文學(xué)院');
INSERT INTO `depts` VALUES ('6', '歷史學(xué)院');
INSERT INTO `depts` VALUES ('7', '理學(xué)院');
INSERT INTO `depts` VALUES ('8', '工學(xué)院');
INSERT INTO `depts` VALUES ('9', '農(nóng)學(xué)院');
INSERT INTO `depts` VALUES ('10', '醫(yī)學(xué)院');
INSERT INTO `depts` VALUES ('11', '軍事學(xué)院');
INSERT INTO `depts` VALUES ('12', '管理學(xué)院');
INSERT INTO `depts` VALUES ('13', '藝術(shù)學(xué)院');


再建立一個(gè)學(xué)生表,再隨便往里面插入點(diǎn)數(shù)據(jù):
復(fù)制代碼 代碼如下:

-- ----------------------------
-- Table structure for `students`
-- ----------------------------
DROP TABLE IF EXISTS `students`;
CREATE TABLE `students` (
  `stuNo` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '學(xué)號(hào) 從1000開始',
  `deptId` int(10) unsigned NOT NULL COMMENT '學(xué)院ID',
  `stuName` varchar(50) NOT NULL COMMENT '學(xué)生姓名',
  PRIMARY KEY (`stuNo`),
  KEY `FK_DEPTID` (`deptId`),
  CONSTRAINT `FK_DEPTID` FOREIGN KEY (`deptId`) REFERENCES `depts` (`deptId`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1006 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Records of students
-- ----------------------------
INSERT INTO `students` VALUES ('1000', '13', '鳥叔');
INSERT INTO `students` VALUES ('1001', '7', '喬布斯');
INSERT INTO `students` VALUES ('1002', '3', '阿湯哥');
INSERT INTO `students` VALUES ('1003', '3', '施瓦辛格');
INSERT INTO `students` VALUES ('1004', '2', '貝克漢姆');
INSERT INTO `students` VALUES ('1005', '3', '讓雷諾');


現(xiàn)在我們想統(tǒng)計(jì)一下各個(gè)學(xué)院都有多少學(xué)生。這個(gè)題目在我們學(xué)習(xí)SQL的時(shí)候再簡(jiǎn)單不過(guò)了。兩種實(shí)現(xiàn)方法:

使用Group By和不使用Group By:

復(fù)制代碼 代碼如下:

SELECT b.deptId, b.deptName, count(*) as 'totalCount' FROM students a LEFT JOIN depts b ON a.deptId=b.deptId GROUP BY b.deptId ORDER BY b.deptId;

使用Group By之后,凡是沒(méi)有對(duì)應(yīng)學(xué)生記錄的學(xué)院都沒(méi)有顯示出來(lái)(我不明白為什么。。。如果有人知道的話麻煩告訴我好嗎?)
復(fù)制代碼 代碼如下:

+--------+--------------+------------+
| deptId | deptName     | totalCount |
+--------+--------------+------------+
|      2 | 經(jīng)濟(jì)學(xué)院     |          1 |
|      3 | 法學(xué)院       |          3 |
|      7 | 理學(xué)院       |          1 |
|     13 | 藝術(shù)學(xué)院     |          1 |
+--------+--------------+------------+

再來(lái)一個(gè)不使用Group By的查詢:
復(fù)制代碼 代碼如下:

SELECT a.deptId, a.deptName, (SELECT count(*) FROM students b where b.deptId=a.deptId) as 'totalCount' FROM depts a;

這次就完全顯示出來(lái)了:
復(fù)制代碼 代碼如下:

+--------+--------------+------------+
| deptId | deptName     | totalCount |
+--------+--------------+------------+
|      1 | 哲學(xué)院       |          0 |
|      2 | 經(jīng)濟(jì)學(xué)院     |          1 |
|      3 | 法學(xué)院       |          3 |
|      4 | 教育學(xué)院     |          0 |
|      5 | 文學(xué)院       |          0 |
|      6 | 歷史學(xué)院     |          0 |
|      7 | 理學(xué)院       |          1 |
|      8 | 工學(xué)院       |          0 |
|      9 | 農(nóng)學(xué)院       |          0 |
|     10 | 醫(yī)學(xué)院       |          0 |
|     11 | 軍事學(xué)院     |          0 |
|     12 | 管理學(xué)院     |          0 |
|     13 | 藝術(shù)學(xué)院     |          1 |
+--------+--------------+------------+

至此,我們的SQL寫通了。但是怎么才能使用JPA來(lái)查詢出一樣的視圖呢?

我們按照往常編碼那樣,從一個(gè)主要的實(shí)體操作服務(wù)中暴露出EntityManager來(lái):

復(fù)制代碼 代碼如下:

package net.csdn.blog.chaijunkun.dao;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.springframework.stereotype.Service;

@Service
public class ObjectDaoServiceImpl implements ObjectDaoService {

 @PersistenceContext
 private EntityManager entityManager;

 @Override
 public EntityManager getEntityManager(){
  return this.entityManager;
 }

}


這樣做的好處就是所有的數(shù)據(jù)操作都來(lái)源于同一個(gè)實(shí)體管理器。將來(lái)若部署發(fā)生變化,只改這一處注入就可以了。

然后我們還需要和以前一樣構(gòu)造兩個(gè)表的實(shí)體類:

學(xué)院表的實(shí)體類:

復(fù)制代碼 代碼如下:

package net.csdn.blog.chaijunkun.pojo;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="depts")
public class Depts implements Serializable {

 /**
  *
  */
 private static final long serialVersionUID = 3602227759878736655L;

 @Id
 @GeneratedValue(strategy= GenerationType.AUTO)
 @Column(name= "deptId")
 private Integer deptId;

 @Column(name= "deptName", length= 50, nullable= false)
 private String deptName;

 //getters and setters...
}


學(xué)生表的實(shí)體類:
復(fù)制代碼 代碼如下:

package net.csdn.blog.chaijunkun.pojo;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name= "students")
public class Students implements Serializable {

 /**
  *
  */
 private static final long serialVersionUID = -5942212163629824609L;

 @Id
 @GeneratedValue(strategy= GenerationType.AUTO)
 @Column(name= "stuNo")
 private Long stuNo;

 @ManyToOne
 @JoinColumn(name= "deptId", nullable= false)<SPAN style="WHITE-SPACE: pre"> </SPAN>
 private Depts depts;

 @Column(name= "stuName", length= 50, nullable= false)
 private String stuName;

 //getters and setters...

}


兩個(gè)實(shí)體類都構(gòu)造好了,我們接下來(lái)還要弄一個(gè)視圖類,屬性的類型完全由你想要的結(jié)構(gòu)來(lái)構(gòu)造。例如這個(gè)例子中我們要學(xué)院編號(hào),學(xué)院名稱和總?cè)藬?shù)。那么我們就這么定義:
復(fù)制代碼 代碼如下:

package net.csdn.blog.chaijunkun.pojo;

import java.io.Serializable;

public class Report implements Serializable {

 /**
  *
  */
 private static final long serialVersionUID = 4497500574990765498L;

 private Integer deptId;

 private String deptName;

 private Integer totalCount;

 public Report(){};

 public Report(Integer deptId, String deptName, Integer totalCount) {
  this.deptId = deptId;
  this.deptName = deptName;
  this.totalCount = totalCount;
 }

 //getters and setters...

}


可以說(shuō),視圖對(duì)象的定義比實(shí)體定義還要簡(jiǎn)單,不需要注解,不需要映射(以上代碼為了減少代碼量均省去了各屬性的get和set方法,請(qǐng)自行添加)。但是唯一不同的是我們需要額外構(gòu)造一個(gè)帶有字段初始化的構(gòu)造函數(shù)。并且還不能覆蓋默認(rèn)的無(wú)參構(gòu)造函數(shù)。然后我們就開始進(jìn)入真正的查詢了(作為視圖來(lái)講,SQL規(guī)范中是不允許修改數(shù)據(jù)的。因此,視圖僅有SELECT特性。這也是為什么很多人使用JPA想通過(guò)實(shí)體映射數(shù)據(jù)庫(kù)內(nèi)建視圖的方式進(jìn)行查詢,卻始終映射不成功的癥結(jié)所在。
復(fù)制代碼 代碼如下:

package net.csdn.blog.chaijunkun.dao;

import java.util.List;

import javax.annotation.Resource;
import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;

import org.springframework.stereotype.Service;

import net.csdn.blog.chaijunkun.pojo.Depts;
import net.csdn.blog.chaijunkun.pojo.Report;
import net.csdn.blog.chaijunkun.pojo.Students;

@Service
public class ReportServiceImpl implements ReportService {

 @Resource
 private ObjectDaoService objectDaoService;

 @Override
 public List<Report> getReport() {
  String jpql= String.format("select new %3$s(a.deptId, a.deptName, (select count(*) from %2$s b where b.deptId= a.deptId) as totalCount) from %1$s a",
    Depts.class.getName(),
    Students.class.getName(),
    Report.class.getName());

  EntityManager entityManager= objectDaoService.getEntityManager();
  //建立有類型的查詢
  TypedQuery<Report> reportTypedQuery= entityManager.createQuery(jpql, Report.class);
  //另外有詳細(xì)查詢條件的在jpql中留出參數(shù)位置來(lái)(?1 ?2 ?3....),然后在這設(shè)置
  //reportTypedQuery.setParameter(1, params);
  List<Report> reports= reportTypedQuery.getResultList();
  return reports;
 }

}


在上面的代碼中我們構(gòu)造了JPQL中的視圖查詢語(yǔ)句。最重要的就是要在最初的select后面new出新的對(duì)象。然后把我們查詢到的結(jié)果通過(guò)視圖對(duì)象的構(gòu)造函數(shù)灌入各個(gè)屬性。由統(tǒng)計(jì)生成的字段最好用as重命名結(jié)果以保持和視圖對(duì)象屬性名稱相同。這樣,我們就得到了視圖數(shù)據(jù)。接下來(lái)就去嘗試遍歷這個(gè)List吧,操作非常方便。

另外,向大家推薦一本書——Apress出版社出版的《Pro JPA 2 Mastering the Java trade Persistence API》,這本書詳細(xì)介紹了JPA的相關(guān)技術(shù),非常實(shí)用。

相關(guān)文章

  • SpringBoot log打印及輸出方式

    SpringBoot log打印及輸出方式

    這篇文章主要介紹了SpringBoot log打印及輸出方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • Java實(shí)體類不要使用基本類型的知識(shí)點(diǎn)總結(jié)

    Java實(shí)體類不要使用基本類型的知識(shí)點(diǎn)總結(jié)

    在本篇文章里小編給大家整理的是關(guān)于Java包裝類之實(shí)體類不要使用基本類型的知識(shí)點(diǎn)內(nèi)容,需要的朋友們可以學(xué)習(xí)下。
    2020-02-02
  • mybatis-plus?分頁(yè)類型轉(zhuǎn)換工具類

    mybatis-plus?分頁(yè)類型轉(zhuǎn)換工具類

    用mybatis-plus?的分頁(yè)對(duì)象的時(shí)候,因?yàn)橛胢ybatis-puls?查詢出來(lái)的分頁(yè)對(duì)象的records里的泛型是實(shí)體,有時(shí)候需要將實(shí)體轉(zhuǎn)換為前端展示的對(duì)象,所有寫了一個(gè)分頁(yè)數(shù)據(jù)的類型轉(zhuǎn)換工具,解決這個(gè)問(wèn)題,對(duì)mybatis-plus?分頁(yè)工具類相關(guān)知識(shí)感興趣的朋友一起看看吧
    2022-03-03
  • 淺談SpringBoot內(nèi)嵌Tomcat的實(shí)現(xiàn)原理解析

    淺談SpringBoot內(nèi)嵌Tomcat的實(shí)現(xiàn)原理解析

    這篇文章主要介紹了淺談SpringBoot內(nèi)嵌Tomcat的實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • 一文詳解Java線程的6種狀態(tài)與生命周期

    一文詳解Java線程的6種狀態(tài)與生命周期

    一個(gè)線程在給定的時(shí)間點(diǎn)只能處于一種狀態(tài)。線程可以有6種狀態(tài):New、Runnable、Blocked、Waiting、Timed?waiting和Terminated。本文將詳細(xì)講解這6種狀態(tài),需要的可以參考一下
    2022-05-05
  • Java使用FTP上傳文件并模擬接受的方法

    Java使用FTP上傳文件并模擬接受的方法

    這篇文章主要介紹了Java使用FTP上傳文件并模擬接受的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-02-02
  • 淺談Java中類的實(shí)例化步驟

    淺談Java中類的實(shí)例化步驟

    今天小編就為大家分享一篇關(guān)于淺談Java中類的實(shí)例化步驟,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-02-02
  • 基于Ok+Rxjava實(shí)現(xiàn)斷點(diǎn)續(xù)傳下載

    基于Ok+Rxjava實(shí)現(xiàn)斷點(diǎn)續(xù)傳下載

    這篇文章主要為大家詳細(xì)介紹了基于Ok+Rxjava實(shí)現(xiàn)斷點(diǎn)續(xù)傳下載,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-06-06
  • Java將String字符串帶括號(hào)轉(zhuǎn)成List的簡(jiǎn)單方法

    Java將String字符串帶括號(hào)轉(zhuǎn)成List的簡(jiǎn)單方法

    Java中我們有時(shí)需要對(duì)現(xiàn)有的字符串進(jìn)行切割并轉(zhuǎn)化成一個(gè)List集合,這篇文章主要給大家介紹了關(guān)于Java將String字符串帶括號(hào)轉(zhuǎn)成List的簡(jiǎn)單方法,需要的朋友可以參考下
    2023-03-03
  • Java中StringUtils工具類的一些用法實(shí)例

    Java中StringUtils工具類的一些用法實(shí)例

    這篇文章主要介紹了Java中StringUtils工具類的一些用法實(shí)例,本文著重講解了isEmpty和isBlank方法的使用,另外也講解了trim、strip等方法的使用實(shí)例,需要的朋友可以參考下
    2015-06-06

最新評(píng)論

且末县| 新沂市| 慈利县| 康保县| 青冈县| 奉贤区| 晋城| 基隆市| 漠河县| 秀山| 桐梓县| 张家口市| 榆社县| 伊宁县| 威远县| 湘乡市| 左权县| 泰和县| 东乡| 安岳县| 神池县| 沽源县| 上高县| 江油市| 高阳县| 潍坊市| 越西县| 孟村| 庆安县| 石首市| 宜丰县| 五莲县| 平阳县| 界首市| 洪湖市| 靖安县| 巴林右旗| 临猗县| 日喀则市| 湘潭县| 晋州市|