快速入门 TypeORM

介绍

TypeORM 是一个流行的 TypeScript 和 JavaScript ORM(对象关系映射)工具,它支持使用 MySQL、PostgreSQL、SQLite、Microsoft SQL Server、Oracle 以及 MongoDB 等多种数据库。

TypeORM 旨在提供一种有效的方式来管理数据库操作,并通过实体和数据库表之间的映射来简化数据层的开发。它可以在 Node.js 环境中运行,特别适合于使用 TypeScript 编写的应用程序。

初始化配置

新建一个 TypeORM 项目:

bash 复制代码
npx typeorm@latest init --name typeorm-test --database mysql

在 data-source.ts 改下用户名密码数据库,把连接 msyql 的驱动包改为 mysql2,并修改加密方式:

typescript 复制代码
// 支持装饰器的元数据反射功能
import 'reflect-metadata';
import { DataSource } from 'typeorm';
import { User } from './entity/User';

// 配置和管理数据库连接
export const AppDataSource = new DataSource({
	type: 'mysql', // 指定数据库类型为 MySQL
	host: 'localhost', // 数据库主机地址,这里设置为本地主机
	port: 3306, // MySQL 数据库的默认端口号
	username: 'root', // 数据库连接的用户名
	password: 'xxx', // 数据库连接的密码,这里应替换为实际密码
	database: 'typeorm_test', // 要连接的数据库名称
	synchronize: true, // 设置为 true 以允许 TypeORM 自动创建或更新数据库表结构
	logging: true, // 开启日志记录,以便于调试和监控数据库操作
	entities: [User], // 注册实体到当前数据源,这里只注册了 User 实体
	migrations: [], // 迁移文件的数组,这里为空表示没有迁移文件
	subscribers: [], // 订阅者文件的数组,这里为空表示没有订阅者文件
	poolSize: 10, // 连接池的大小,这里设置为 10
	connectorPackage: 'mysql2', // 指定连接器包为 'mysql2',这是一个 MySQL 客户端库
	extra: {
		authPlugin: 'sha256_password', // 额外的数据库连接选项,这里指定使用 'sha256_password' 认证插件
	},
});

安装 mysql2:

bash 复制代码
npm install mysql2

在 mysql workbench 里创建个 database:

sql 复制代码
CREATE DATABASE `typeorm_test` DEFAULT CHARACTER SET utf8mb4;

初始化自带的 User Entity:

这个 Entity 映射的主键为 INT 自增,name 是 VARCHAR(255),age 是 INT。

启动项目:

bash 复制代码
npm run start

user 表有条数据:

在这里插入的:

Column 装饰器

如果我们想 numbe 类型映射 DOUBLE 呢?string 类型映射 TEXT (长文本)呢?

这时候就需要往 @Column 装饰器传入选项,常用的选项有这些:

  1. type:指定列的数据库类型。例如:varchar, int, boolean, text 等。如果不指定,TypeORM 会根据属性的数据类型自动推断。
typescript 复制代码
@Column({ type: 'varchar' })
name: string;
  1. length:为某些列类型指定长度,常用于字符串类型。
typescript 复制代码
@Column({ type: 'varchar', length: 150 })
name: string;
  1. nullable:标示该列是否可以存储 null 值,默认为 false
typescript 复制代码
@Column({ nullable: true })
nickname: string | null;
  1. default:为列指定一个默认值。
typescript 复制代码
@Column({ default: 'new user' })
username: string;
  1. unique:确保列的值在整个表中是唯一的。
typescript 复制代码
@Column({ unique: true })
email: string;
  1. primary:标示该列是否为表的主键。
typescript 复制代码
@Column({ primary: true })
id: number;
  1. update:指定该列的值在使用实体保存时是否可以被更新,默认为 true
typescript 复制代码
@Column({ update: false })
createdAt: Date;
  1. select:指定在通过实体管理器或仓库API查询时,该列是否默认被选中,默认为 true
typescript 复制代码
@Column({ select: false })
password: string;
  1. precision 和 scale:用于 decimalnumeric 类型的列,指定小数点前的数字个数(精度)和小数点后的数字个数(刻度)。
typescript 复制代码
@Column({ type: 'decimal', precision: 5, scale: 2 })
price: number;
  1. comment:为列添加注释。
typescript 复制代码
@Column({ comment: '用户的名字' })
name: string;
  1. array:特定于 PostgreSQL,用于指定列是否为数组类型。
typescript 复制代码
@Column({ type: 'int', array: true })
numbers: number[];

我们新增了一个 Test 实体:

typescript 复制代码
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

// 使用typeorm定义一个名为Test的数据库表
@Entity({
	name: 'Test', // 指定表名为Test
})
export class Test {
	// 使用PrimaryGeneratedColumn装饰器定义一个自动生成的主键列
	@PrimaryGeneratedColumn({
		comment: '这是id', // 为该列添加注释说明这是id
	})
	id: number; // 定义一个名为id的数字类型字段,作为主键

	// 使用Column装饰器定义一个普通列
	@Column({
		name: 'aa1', // 指定列名为aa1
		type: 'text', // 指定列类型为text
		comment: '这是a1', // 为该列添加注释说明这是a1
	})
	a1: string; // 定义一个名为a1的字符串类型字段

	// 使用Column装饰器定义一个具有特殊约束的列
	@Column({
		unique: true, // 该列值必须唯一
		nullable: false, // 该列不允许为空
		length: 10, // 该列的最大长度为10
		type: 'varchar', // 指定列类型为varchar
		default: '默认值', // 为该列设置默认值为"默认值"
	})
	b2: string; // 定义一个名为b2的字符串类型字段

	// 使用Column装饰器定义一个双精度浮点数列
	@Column({
		type: 'double', // 指定列类型为double
	})
	c3: number; // 定义一个名为c3的数字类型字段,存储双精度浮点数
}

然后在 DataSource 的 entities 里引入下:

重新 npm run start,生成了对应的表:

增删改查

初始化与实体创建

创建 User 实体并保存到数据库:

typescript 复制代码
import { AppDataSource } from "./data-source";
import { User } from "./entity/User";

AppDataSource.initialize().then(async () => {
    const user = new User();
    user.firstName = "mu";
    user.lastName = "yun";
    user.age = 25;

    await AppDataSource.manager.save(user);
}).catch(error => console.log(error));

增加、修改记录

要向数据库中插入记录,可以使用 save 方法。如果未指定 id,则会创建新记录;如果指定了 id,则会更新对应的记录:

typescript 复制代码
const user = new User();
user.id = 1; // 指定 id 时,会更新 id 为 1 的记录
user.firstName = "yu";
user.lastName = "dai";
user.age = 25;

await AppDataSource.manager.save(user);

其实 EntityManager 有 update 和 insert 方法,分别是修改和插入的,但是它们不会先 select 查询一次。

而 save 方法会先查询一次数据库来确定是插入还是修改。

批量操作

批量插入:

typescript 复制代码
await AppDataSource.manager.save(User, [
    { firstName: 'n1', lastName: 'n1', age: 21 },
    { firstName: 'n2', lastName: 'n2', age: 22 },
    { firstName: 'n3', lastName: 'n3', age: 23 }
]);

批量修改:

typescript 复制代码
await AppDataSource.manager.save(User, [
    { id: 2, firstName: 'n4', lastName: 'n4', age: 21 },
    { id: 3, firstName: 'n5', lastName: 'n5', age: 22 },
    { id: 4, firstName: 'n6', lastName: 'n6', age: 23 }
]);

删除记录

删除操作可以使用 delete 方法,传入实体类和要删除的记录的 id 或 id 数组。

也可以使用 remove 方法,传入要删除的实体对象:

typescript 复制代码
await AppDataSource.manager.delete(User, 1); // 删除 id 为 1 的记录
await AppDataSource.manager.delete(User, [2, 3]); // 删除 id 为 2 和 3 的记录

const user = new User();
user.id = 1;
await AppDataSource.manager.remove(User, user); // 删除 user 实体对应的记录

查询记录

find(查询多条记录):

指定查询的 where 条件是 id 为 4-8,指定 select 的列为 firstName 和 age,然后 order 指定根据 age 升序排列。

不带第二个查询条件参数,就是查询所有用户。

findOne(查询单条记录):

指定查询的 where 条件是 id 为 4 ,指定 select 的列为 firstName 和 age,然后 order 指定根据 age 升序排列。

findBy(根据条件查询记录集合),比较适合简单查询场景:

typescript 复制代码
const usersByAge = await AppDataSource.manager.findBy(User, { age: 23 }); // 查询年龄为 23 的用户

findAndCount 获取记录及其数量:

findOneOrFail 或者 findOneByOrFail 方法在未找到记录时抛出异常:

直接执行 SQL 语句

如果需要执行复杂的 SQL 语句,例如多个 Entity 的关联查询,可以使用 query 方法或 createQueryBuilder 方法:

typescript 复制代码
const users = await AppDataSource.manager.query('SELECT * FROM user WHERE age IN (?, ?)', [21, 22]);

const queryBuilder = AppDataSource.manager.createQueryBuilder();
const user = await queryBuilder
    .select("user")
    .from(User, "user")
    .where("user.age = :age", { age: 21 })
    .getOne();

事务处理

在处理关联数据的增删改时,可以使用 transaction 方法确保操作的原子性:

typescript 复制代码
await AppDataSource.manager.transaction(async manager => {
    await manager.save(User, {
        id: 4,
        firstName: 'mu',
        lastName: 'yun',
        age: 20
    });
});

简化操作

为了简化调用每个方法的时候都要先传入实体类操作,可以使用 getRepository 方法获取实体的仓库对象,然后调用增删改查方法:

typescript 复制代码
const userRepository = AppDataSource.getRepository(User);
// 使用 userRepository 进行操作
相关推荐
求知若饥6 分钟前
NestJS 项目实战-权限管理系统开发(六)
后端·node.js·nestjs
ZJ_.11 分钟前
WPSJS:让 WPS 办公与 JavaScript 完美联动
开发语言·前端·javascript·vscode·ecmascript·wps
GIS开发特训营15 分钟前
Vue零基础教程|从前端框架到GIS开发系列课程(七)响应式系统介绍
前端·vue.js·前端框架·gis开发·webgis·三维gis
Cachel wood41 分钟前
python round四舍五入和decimal库精确四舍五入
java·linux·前端·数据库·vue.js·python·前端框架
学代码的小前端43 分钟前
0基础学前端-----CSS DAY9
前端·css
gb42152871 小时前
springboot中Jackson库和jsonpath库的区别和联系。
java·spring boot·后端
joan_851 小时前
layui表格templet图片渲染--模板字符串和字符串拼接
前端·javascript·layui
程序猿进阶1 小时前
深入解析 Spring WebFlux:原理与应用
java·开发语言·后端·spring·面试·架构·springboot
m0_748236111 小时前
Calcite Web 项目常见问题解决方案
开发语言·前端·rust