TypeORM 基础篇:项目初始化与增删改查全流程

ORM 是 Object-Relational Mapping 的缩写,即对象关系映射。 也就是说把关系型数据库的表映射成面向对象的 class,表的字段映射成对象的属性映射,表与表的关联映射成属性的关联。

初始化 TypeORM 项目

kotlin 复制代码
npx typeorm@latest init --name typeorm-all-feature --database mysql

连接配置

javascript 复制代码
// src/data-source.ts
import "reflect-metadata"
import {DataSource} from "typeorm"
import {User} from "./entity/User"
​
export const AppDataSource = new DataSource({
  type: "mysql", // 数据库类型,postgres/mysql/mariadb/sqlite/oracle/mssql/cockroachdb
  host: "localhost", // 数据库主机
  port: 3306, // 数据库端口
  username: "root", // 数据库用户名
  password: "admin", // 数据库密码
  database: "hello-mysql", // 数据库名称
  synchronize: true, // 是否自动同步数据库表结构
  logging: true, // 是否打印 typeorm 生成的 sql 语句
  entities: [User], // 指定有哪些数据库的表对应的实体(Entity);也可以通过这种方式指定: ['./**/entity*.ts']
  migrations: [], // 迁移文件
  subscribers: [], // Entity 声明周期的订阅者,比如 insert/update/remove 前后,可以加入一些逻辑
  poolSize: 10, // 数据库连接池中连接的最大连接数
  connectorPackage: "mysql2", // 指定用的数据库连接器包
  extra: { // 额外发送给连接器包的参数
    authPlugins: 'sha256_password'
  }
})

安装 mysql2

css 复制代码
npm install --save mysql2

实体

实体(Entity)是数据库中的表,实体类是 TypeScript 中的类,实体类与数据库表结构一一对应。

less 复制代码
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm"
​
@Entity()
export class User {
​
  @PrimaryGeneratedColumn()
  id: number
​
  @Column()
  firstName: string
​
  @Column()
  lastName: string
​
  @Column()
  age: number
​
}
  • 默认映射关系: 主键为 int 类型、自增;string 类型为 varchar(255);number 类型为 int 类型;
  • 修改映射类型则通过 type 属性指定,type 为数据库中对应的类型
less 复制代码
// src/entity/Sanshi.ts
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
​
@Entity({
  name: 'san_shi' // 指定表名,默认表名是类名
})
export class Sanshi {
​
  // @PrimaryGeneratedColumn() // 默认 int 类型,自增
  @PrimaryGeneratedColumn({
    comment: '这是 id' // 添加注释
  })
  id: number
​
  // @Column() // 默认 varchar(255)
  @Column({
    name: 'key',
    type: 'text', // 指定字段类型,默认 varchar(255)
    comment: '这是 key'
  })
  key: string
​
  @Column({
    unique: true, // 添加唯一索引
    nullable: false, // 允许为 null
    length: 10, // 指定字段长度
    type: 'varchar',
    default: 'label'
  })
  label: string
​
  // @Column() // 默认 int 类型
  @Column({
    type: 'double', // 指定字段类型,默认 int
  })
  value: number
}

同步修改到数据库

arduino 复制代码
npm run start

新增

javascript 复制代码
// src/index.ts
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
​
  const user = new User()
  // user.id = 1 // 不指定 id 是新增,指定则是修改
  user.firstName = "San"
  user.lastName = "Shi"
  user.age = 18
  await AppDataSource.manager.save(user)
​
}).catch(error => console.log(error))

批量新增

csharp 复制代码
// 批量插入
const personArr = [
  { firstName: "San1", lastName: "Shi1", age: 18},
  { firstName: "San2", lastName: "Shi2", age: 18},
  { firstName: "San3", lastName: "Shi3", age: 18},
]
await AppDataSource.manager.save(Person, personArr)

编辑

javascript 复制代码
// src/index.ts
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
​
  const user = new User()
  user.id = 1 // 不指定 id 是新增,指定则是修改
  user.firstName = "San"
  user.lastName = "Shi"
  user.age = 18
  await AppDataSource.manager.save(user)
  console.log("Saved a new user with id: " + user.id)
​
}).catch(error => console.log(error))

批量修改

yaml 复制代码
// 批量修改
const personArr = [
  { id: 1, firstName: "San1", lastName: "Shi1", age: 17},
  { id: 2, firstName: "San2", lastName: "Shi2", age: 18},
  { id: 4, firstName: "San0", lastName: "Shi0", age: 19},
]
await AppDataSource.manager.save(Person, personArr)

EntityManager 还有 update 和 insert 方法,分别是修改和插入,但是它们不会先 select 一次,而 save 方法会先查询一次数据库来确定是插入还是修改。

删除和批量删除

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
​
  // 删除
  await AppDataSource.manager.delete(User, 1)
  // 批量删除
  await AppDataSource.manager.delete(User, [2, 3])
​
}).catch(error => console.log(error))
​

删除方法 delete 和 remove 的区别

delete 和 remove 的区别是,delete 直接传 id、而 remove 则是传入 entity 对象。

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
​
  // 通过 remove 删除
  const rUser = new User();
  rUser.id = 4;
  await AppDataSource.manager.remove(User, rUser);
​
}).catch(error => console.log(error))
​

查询

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
​
  // 查询
  const users = await AppDataSource.manager.find(User);
  console.log('查询结果: ', users);
​
}).catch(error => console.log(error))
​

条件查询

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
  
  // 条件查询
  const users2 = await AppDataSource.manager.findBy(User, {
    firstName: 'San'
  });
  console.log('条件查询结果: ', users2);
​
}).catch(error => console.log(error))
​
javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
​
AppDataSource.initialize().then(async () => {
​
  /**
   * 条件查询2:
   * In: 批量查询
   */
  const users3 = await AppDataSource.manager.find(User, {
    select: {
      firstName: true,
      age: true
    },
    where: {
      id: In([12, 13, 9]) // 批量查询,id 为 12、13、9 的数据
    },
    order: {
      age: 'ASC'
    }
  })
  console.log('条件查询结果2: ', users3);
​
}).catch(error => console.log(error))
​

查询并统计

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
​
  // 查询并统计有多少条记录
  const count = await AppDataSource.manager.findAndCount(User)
  console.log('查询并统计有多少条记录: ', count);
​
}).catch(error => console.log(error))
​

查询并按条件统计

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
  
  // 查询并按条件统计
  const count2 = await AppDataSource.manager.findAndCountBy(User, {
    firstName: 'San'
  })
  console.log('查询并按条件统计: ', count2);
​
}).catch(error => console.log(error))
​

查询单条

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
​
AppDataSource.initialize().then(async () => {
​
  // 查询单条
  const user2 = await AppDataSource.manager.findOne(User, {
    select: {
      firstName: true,
      age: true
    },
    where: {
      id: 13
    },
    order: {
      age: 'ASC'
    }
  });
  console.log('单条查询结果: ', user2);
​
}).catch(error => console.log(error))
​

查询单条并按条件查询

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
​
AppDataSource.initialize().then(async () => {
  
  // 查询单条并按条件查询
  const user3 = await AppDataSource.manager.findOneBy(User, {
    age: 18
  })
  console.log('单条并按条件查询结果: ', user3);
​
}).catch(error => console.log(error))
​

查询单条,查不到时返回异常信息

使用 findOneOrFail 和 findOneByOrFail 在查询不到时会抛出一个 EntityNotFoundError 的异常

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
​
AppDataSource.initialize().then(async () => {
  
  // 查询单条,查不到时返回异常信息
  const user4 = await AppDataSource.manager.findOneOrFail(User, {
    where: {
      id: 9999
    }
  })
  console.log('单条,查不到时返回异常信息(findOneOrFail): ', user4);
​
  const user5 = await AppDataSource.manager.findOneByOrFail(User, {
    id: 9999
  })
  console.log('查询单条,查不到时返回异常信息(findOneByOrFail): ', user5);
​
}).catch(error => console.log(error))
​

使用 query 执行 SQL

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
​
AppDataSource.initialize().then(async () => {
  
  // 使用 query 执行 SQL
  const user6 = await AppDataSource.manager.query('SELECT * FROM user WHERE id = 16')
  console.log('使用 query 执行 SQL: ', user6);
​
}).catch(error => console.log(error))
​

使用 queryBuilder

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
​
AppDataSource.initialize().then(async () => {
  
  // 使用 queryBuilder
  const queryBuilder = await AppDataSource.manager.createQueryBuilder()
  const user7 = await queryBuilder.select('user')
    .from(User, 'user')
    .where('user.id = :id', { id: 17 })
    .getOne()
  console.log('使用 queryBuilder 查询结果: ', user7);
​
}).catch(error => console.log(error))
​

开启事务

用 transaction 方法包裹即可。

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
​
AppDataSource.initialize().then(async () => {
  
  // 开启事务
  await AppDataSource.manager.transaction(async entityManager => {
    const user = new User()
    user.firstName = "San"
    user.lastName = "Shi"
    user.age = 18
    await entityManager.save(user)
  })
​
}).catch(error => console.log(error))
​

避免调用每个方法时都传入实体类

可以先调用 getRepository 传入 Entity,拿到专门处理这个 Entity 的增删改查的类,再调用各种方法。

javascript 复制代码
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
​
AppDataSource.initialize().then(async () => {
  
  // 避免调用每个方法时都传入实体类
  const userManager = AppDataSource.manager.getRepository(User)
  const users4 = await userManager.find({
    select: {
      firstName: true,
      age: true
    },
  })
  console.log('避免调用每个方法时都传入实体类,查询结果: ', users4);
​
  const user4 = await userManager.findOne({
    select: {
      firstName: true,
      age: true
    },
    where: {
      id: 13
    },
    order: {
      age: 'ASC'
    }
  })
  console.log('避免调用每个方法时都传入实体类,单条查询结果: ', user4);
​
}).catch(error => console.log(error))
​
相关推荐
BingoGo3 小时前
现代 PHP8+ 实战特性介绍 Enums、Fibers 和 Attributes
后端·php
小时前端3 小时前
事件委托性能真相:90%内存节省背后的数据实证
前端·dom
半木的不二家3 小时前
全栈框架Elpis实战项目-里程碑一
前端
超能996要躺平3 小时前
用三行 CSS 实现任意多列等分布局:深入掌握 Grid 的 repeat() 与 gap
前端·css
我叫黑大帅3 小时前
面对组件的不听话,我还是用了它…………
前端·javascript·vue.js
啥也不会的码农3 小时前
Eslint9发布都一年了,你确定还不了解下?
前端·eslint
泉城老铁3 小时前
tomcat 部署springboot,线程经常断开导致数据库连接池关闭,如何解决
java·spring boot·后端
白衣鸽子3 小时前
JavaDoc:自动化生成的可维护代码说明书
后端·代码规范
戴维南3 小时前
TypeScript 与 Vue 编辑器协同机制详解
前端