TypeORM - 查詢構建器



查詢構建器用於以簡單的方式構建複雜的 SQL 查詢。它從 Connection 方法和 QueryRunner 物件初始化。

我們可以透過三種方式建立 QueryBuilder。

連線

考慮一個使用連線方法使用 QueryBuilder 的簡單示例。

import {getConnection} from "typeorm"; 

const user = await getConnection() .createQueryBuilder() 
.select("user") 
.from(User, "user") 
.where("user.id = :id", { id: 1 }) .getOne();

實體管理器

讓我們如下建立使用實體管理器的查詢構建器:

import {getManager} from "typeorm"; 

const user = await getManager() .createQueryBuilder(User, "user") .where("user.id = :id", { id: 1 })    .getOne();

Repository

我們可以使用 repository 建立查詢構建器。如下所述:

import {getRepository} from "typeorm"; 

const user = await getRepository(User) .createQueryBuilder("user") .where("user.id = :id", { id: 1 }) .getOne();

別名

別名與 SQL 別名相同。我們使用 QueryBuilder 為 Student 表建立別名,如下所示:

import {getConnection} from "typeorm"; 

const user = await getConnection() .createQueryBuilder() 
.select("stud") 
.from(Student, "stud")

此查詢等效於:

select * from students as stud

引數

引數 用作查詢中動態值的佔位符。在許多情況下,查詢不同實體物件的查詢將相同,除了值。例如,查詢不同學生的查詢相同,除了學生 ID 資料。在這種情況下,我們可以為學生 ID 使用引數,然後更改引數以獲取不同的學生物件。

引數的另一個重要用途是防止 SQL 注入。它是現代 Web 應用程式中重要的安全漏洞之一。透過在查詢中使用引數,我們可以避免 SQL 注入攻擊。

引數的另一個重要用途是防止 SQL 注入。它是現代 Web 應用程式中重要的安全漏洞之一。透過在查詢中使用引數,我們可以避免 SQL 注入攻擊。

例如

"student.id = :id", { id: 1 }

這裡,

:id - 引數名稱。

{ id: 1 } - 引數的值

新增表示式

本節介紹如何使用表示式。

where

where 用於在條件匹配時過濾記錄。

createQueryBuilder("student") .where("student.id = :id", { id: 1 })

此查詢等效於:

select * from students student where student.id=1;

我們也可以在其中使用 AND、OR、NOT、IN 條件。

having

簡單的 having 表示式定義如下:

createQueryBuilder("student") .having("student.id = :id", { id: 1 })

此查詢等效於:

select * from students student having student.id=1;

orderBy

orderby 用於根據欄位對記錄進行排序。

createQueryBuilder("student") .orderBy("student.name")

此查詢等效於:

select * from students student order by student.name;

groupBy

它用於根據指定的列對記錄進行分組。

createQueryBuilder("student") .groupBy("student.id")

此查詢等效於:

select * from students student group by student.id;

limit

它用於限制行的選擇。下面,示例顯示瞭如何在查詢構建器中使用 limit:

createQueryBuilder("student") .limit(5)

此查詢等效於:

select * from students student limit 5;

offset

Offset 用於指定跳過多少行結果。它定義如下:

createQueryBuilder("student") .offset(5)

此查詢等效於:

select * from students student offset 5;

joins

join 子句用於根據相關列組合來自兩個或多個表的行。考慮兩個實體:

Student.ts

import {Entity, PrimaryGeneratedColumn, Column, OneToMany} from "typeorm"; 
import {Project} from "./Project"; 

@Entity() 
export class User {
   
   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   name: string; 
   
   @OneToMany(type => Project, project => project.student) projects: project[]; 
}

Project.ts

import {Entity, PrimaryGeneratedColumn, Column, ManyToOne} from "typeorm"; 
import {Student} from "./Student"; 

@Entity() 
export class Project { 

   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   title: string; 
   
   @ManyToOne(type => Student, student => student.projects) student: Student; 
}

讓我們使用以下查詢執行簡單的左連線:

const student = await createQueryBuilder("student") .leftJoinAndSelect("student.projects", "project") 
.where("student.name = :name", { name: "Student1" }) 
.getOne();

此查詢等效於:

SELECT student.*, project.* FROM students student 
   LEFT JOIN projects project ON project.student = student.id 
   WHERE student.name = 'Student1'

類似地,我們也可以嘗試內部連線。

不帶選擇的連線

我們可以不使用 select 連線資料。讓我們使用內部連線嘗試此示例,如下所示:

const student = await createQueryBuilder("student") .innerJoin("student.projects", "project") 
   .where("student.name = :name", { name: "student1" }) 
   .getOne();

以上查詢等效於:

SELECT student.* FROM students student 
   INNER JOIN projects project ON project.student = student.id 
   WHERE student.name = 'Student1';

分頁

如果您的應用程式中有更多資料,則需要分頁、頁面滑塊或滾動功能。

例如,如果要顯示應用程式中前五個學生的專案,

const students = await getRepository(Student) .createQueryBuilder("student") .leftJoinAndSelect("student.projects", "project") 
   .take(5) 
   .getMany();

子查詢

稱為另一個查詢或巢狀查詢中的查詢。我們在 FROM、WHERE 和 JOIN 表示式中使用子查詢。

簡單的示例如下所示:

const projects = await connection .createQueryBuilder() .select("project.id", "id")
.addSelect(subQuery => { 
   return subQuery 
      .select("student.name", "name") .from(Student, "student") 
      .limit(1); 
}, "name")
.from(Project, "project") .getMany();

隱藏欄位

如果您的任何列欄位標記為 {select: false},則該列被視為隱藏列。考慮以下實體:

import {Entity, PrimaryGeneratedColumn, Column} from "typeorm"; 

@Entity() 
export class Student {

   @PrimaryGeneratedColumn() 
   id: number; 
   
   @Column() 
   name: string; 
   
   @Column({select: false}) 
   address: string; 
}

這裡,

address 欄位標記為隱藏。我們可以使用addSelect 方法從列中檢索資訊。它定義如下:

const student = await connection.getRepository(Student) .createQueryBuilder() .select("student.id", "student")    .addSelect("student.address") .getMany();

getSql()

此方法用於獲取查詢構建器生成的 SQL 查詢。它定義如下:

const sql = createQueryBuilder("student") .where("student.name = :name", { name: "Student1" })  .orWhere("student.age = :age", { age: 14 }) 
.getSql();
廣告