TypeORM - Trình tạo truy vấn

Trình tạo truy vấn được sử dụng để xây dựng các truy vấn SQL phức tạp một cách dễ dàng. Nó được khởi tạo từ phương thức Connection và các đối tượng QueryRunner.

Chúng ta có thể tạo QueryBuilder theo ba cách.

Kết nối

Hãy xem xét một ví dụ đơn giản về cách sử dụng QueryBuilder bằng phương thức kết nối.

import {getConnection} from "typeorm"; 

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

Người quản lý thực thể

Hãy tạo một trình tạo truy vấn bằng trình quản lý thực thể như sau:

import {getManager} from "typeorm"; 

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

Kho

Chúng ta có thể sử dụng kho lưu trữ để tạo trình tạo truy vấn. Nó được mô tả dưới đây,

import {getRepository} from "typeorm"; 

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

Bí danh

Bí danh giống như bí danh SQL. Chúng tôi tạo bí danh cho bảng Sinh viên bằng QueryBuilder như được mô tả bên dưới -

import {getConnection} from "typeorm"; 

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

Truy vấn này tương đương với,

select * from students as stud

Thông số

Parametersđược sử dụng làm trình giữ chỗ cho các giá trị động trong truy vấn. Trong nhiều trường hợp, truy vấn để tìm đối tượng thực thể khác nhau sẽ giống nhau ngoại trừ các giá trị. Ví dụ: truy vấn tìm sinh viên khác giống nhau ngoại trừStudent IDdữ liệu. Trong trường hợp này, chúng ta có thể sử dụng tham số choStudent ID và sau đó thay đổi tham số để nhận các đối tượng học sinh khác nhau.

Một cách sử dụng quan trọng khác của tham số là ngăn chặn SQL injection. Đây là một trong những vi phạm bảo mật quan trọng trong ứng dụng web hiện đại. Bằng cách sử dụng tham số trong truy vấn, chúng ta có thể sống sót sau các cuộc tấn công SQL injection.

Một cách sử dụng quan trọng khác của tham số là ngăn chặn SQL injection. Đây là một trong những vi phạm bảo mật quan trọng trong ứng dụng web hiện đại. Bằng cách sử dụng tham số trong truy vấn, chúng ta có thể sống sót sau các cuộc tấn công SQL injection.

Ví dụ

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

Đây,

: id - tên tham số.

{id: 1} - giá trị của tham số

Thêm biểu thức

Phần này giải thích về cách sử dụng các biểu thức.

Ở đâu

where được sử dụng để lọc các bản ghi nếu điều kiện được khớp.

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

Truy vấn này tương đương với,

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

Chúng ta cũng có thể sử dụng các điều kiện AND, OR, NOT, IN bên trong.

đang có

Biểu thức có đơn giản được định nghĩa dưới đây:

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

Truy vấn này tương đương với,

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

đặt bởi

orderby được sử dụng để sắp xếp các bản ghi dựa trên trường.

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

Truy vấn này tương đương với,

select * from students student order by student.name;

groupBy

Nó được sử dụng để nhóm các bản ghi dựa trên cột được chỉ định.

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

Truy vấn này tương đương với,

select * from students student group by student.id;

giới hạn

Nó được sử dụng để giới hạn việc lựa chọn các hàng. Dưới đây, ví dụ cho thấy cách sử dụng giới hạn trong trình tạo truy vấn,

createQueryBuilder("student") .limit(5)

Truy vấn này tương đương với,

select * from students student limit 5;

bù lại

Offset được sử dụng để chỉ định, có bao nhiêu hàng để bỏ qua kết quả. Nó được định nghĩa dưới đây -

createQueryBuilder("student") .offset(5)

Truy vấn này tương đương với,

select * from students student offset 5;

tham gia

mệnh đề nối được sử dụng để kết hợp các hàng từ hai hoặc nhiều bảng, dựa trên một cột có liên quan. Hãy xem xét hai thực thể -

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; 
}

Hãy để chúng tôi thực hiện phép nối trái đơn giản bằng cách sử dụng truy vấn dưới đây:

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

Truy vấn này tương đương với,

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

Tương tự, chúng ta cũng có thể thử tham gia nội bộ.

Tham gia mà không cần lựa chọn

Chúng tôi có thể nối dữ liệu mà không cần sử dụng select. Chúng ta hãy thử ví dụ này bằng cách sử dụng phép nối bên trong như sau:

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

Truy vấn trên tương đương với -

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

Phân trang

Nếu bạn có nhiều dữ liệu hơn trong ứng dụng của mình, bạn cần các chức năng phân trang, thanh trượt trang hoặc cuộn.

Ví dụ: nếu bạn muốn hiển thị năm dự án sinh viên đầu tiên trong ứng dụng của mình,

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

truy vấn phụ

Nó được gọi là truy vấn trong một truy vấn khác hoặc truy vấn lồng nhau. Chúng tôi sử dụng truy vấn con trong các biểu thức FROM, WHERE và JOIN.

Ví dụ đơn giản được hiển thị bên dưới -

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

Giấu trang

Nếu bất kỳ trường cột nào của bạn được đánh dấu là {select: false} thì cột đó được coi là cột ẩn. Hãy xem xét thực thể dưới đây -

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

@Entity() 
export class Student {

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

Đây,

address trường được đánh dấu là hidden. Chúng ta có thể sử dụngaddSelectphương pháp để lấy thông tin từ cột. Nó được định nghĩa dưới đây,

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

getSql ()

Phương pháp này được sử dụng để lấy truy vấn SQL được tạo bởi trình tạo truy vấn. Nó được định nghĩa dưới đây -

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