随着前端技术的发展,后端开发也逐渐注重类型安全和开发效率。TypeScript作为一种静态类型语言,可以很好地与JavaScript生态系统集成,而TypeORM则是一个基于TypeScript构建的对象关系映射(ORM)工具,它允许开发者以面向对象的方式操作数据库,同时提供了强大的类型支持。
准备工作
安装Node.js
确保你的机器上已经安装了Node.js,可以通过命令node -v检查版本。
初始化项目
创建一个新的目录作为项目根目录,并在其中初始化一个新的Node.js项目:
mkdir typeorm-tutorial
cd typeorm-tutorial
npm init -y
安装依赖
安装TypeScript、TypeORM以及必要的数据库驱动程序(这里我们以MySQL为例):
npm install typescript typeorm reflect-metadata mysql2
npm install --save-dev @types/node @types/mysql2
接下来,配置TypeScript编译器:
npx tsc --init
编辑tsconfig.json文件,添加以下配置:
{
"compilerOptions": {
"target": "es6",
"module": "commonjs",
"outDir": "./dist",
"strict": true,
"esModuleInterop": true
},
"include": ["src/**/*"]
}
设置数据库连接
在项目的根目录下创建一个名为.ormconfig.json的文件,用于配置TypeORM连接信息:
{
"type": "mysql",
"host": "localhost",
"port": 3306,
"username": "root",
"password": "yourpassword",
"database": "typeorm_tutorial",
"synchronize": true,
"logging": false,
"entities": ["src/entities/*.ts"],
"migrations": [],
"subscribers": [],
"cli": {
"entitiesDir": "src/entities",
"migrationsDir": "src/migrations",
"subscribersDir": "src/subscribers"
}
}
创建实体
实体是TypeORM中的核心概念之一,它代表数据库中的表。我们先定义一个简单的用户实体:
在src/entities目录下创建User.ts文件:
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
email: string;
@Column({ default: '' })
password: string;
}
连接数据库并执行操作
在src/index.ts中设置数据库连接,并编写一些基本的CRUD操作:
import { createConnection } from 'typeorm';
import { User } from './entities/User';
createConnection().then(async connection => {
console.log('Connected to database.');
// 创建新用户
const user = new User();
user.name = 'Alice';
user.email = 'alice@example.com';
user.password = 'secret';
await connection.manager.save(user);
// 查询所有用户
const users = await connection.manager.find(User);
console.log(users);
// 更新用户
const updatedUser = await connection.manager.findOne(User, user.id);
if (updatedUser) {
updatedUser.name = 'Alicia';
await connection.manager.save(updatedUser);
}
// 删除用户
await connection.manager.remove(updatedUser);
await connection.close();
}).catch(error => console.log(error));
运行应用
确保数据库已启动,然后运行:
tsc
node dist/index.js
观察控制台输出,确认数据操作是否成功。
关系管理
在实际应用中,数据通常不是孤立存在的,而是与其他数据之间存在关联。TypeORM 支持多种类型的关系定义,包括一对一(One-to-One)、一对多(One-to-Many)和多对多(Many-to-Many)。
一对一关系
假设我们有两个实体:User 和 Profile。
定义实体:
import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToOne(type => Profile, profile => profile.user)
@JoinColumn()
profile: Profile;
}
@Entity()
export class Profile {
@PrimaryGeneratedColumn()
id: number;
@Column()
bio: string;
@OneToOne(type => User, user => user.profile)
user: User;
}
一对多关系
假设我们有一个 User 实体和一个 Post 实体。
定义实体:
import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@OneToMany(type => Post, post => post.author)
posts: Post[];
}
@Entity()
export class Post {
@PrimaryGeneratedColumn()
id: number;
@Column()
title: string;
@Column()
content: string;
@ManyToOne(type => User, user => user.posts)
author: User;
}
多对多关系
假设我们有一个 User 实体和一个 Group 实体。
定义实体:
import { Entity, Column, PrimaryGeneratedColumn, ManyToMany, JoinTable } from 'typeorm';
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany(type => Group, group => group.users)
@JoinTable()
groups: Group[];
}
@Entity()
export class Group {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@ManyToMany(type => User, user => user.groups)
@JoinTable()
users: User[];
}
自定义查询
TypeORM 提供了多种方式来进行自定义查询,包括使用 QueryBuilder 和原生 SQL 查询。
使用 QueryBuilder
import { getRepository } from 'typeorm';
const userRepository = getRepository(User);
// 查询所有用户
const users = await userRepository.find();
// 查询特定条件下的用户
const usersByName = await userRepository.find({
where: { name: 'Alice' }
});
// 使用 QueryBuilder 进行复杂查询
const queryBuilder = userRepository.createQueryBuilder('user')
.where('user.name = :name', { name: 'Alice' })
.leftJoinAndSelect('user.posts', 'posts')
.getMany();
console.log(await queryBuilder);
使用原生 SQL 查询
import { getConnection } from 'typeorm';
const result = await getConnection()
.query(`SELECT * FROM users WHERE name = :name`, { name: 'Alice' });
console.log(result);
事务处理
事务处理可以确保一系列操作要么全部成功,要么全部失败。TypeORM 提供了事务管理的功能。
import { getConnection } from 'typeorm';
async function performTransaction() {
const userRepo = getConnection().getRepository(User);
const postRepo = getConnection().getRepository(Post);
await getConnection().transaction(async transactionalEntityManager => {
const user = new User();
user.name = 'Alice';
await transactionalEntityManager.save(user);
const post = new Post();
post.title = 'My First Post';
post.content = 'This is my first post.';
post.author = user;
await transactionalEntityManager.save(post);
});
}
performTransaction().catch(error => console.error(error));
迁移管理
TypeORM 提供了迁移管理功能,可以帮助你在开发过程中轻松地管理和更新数据库结构。
创建迁移文件
typeorm migration:create -n AddEmailToUser
这会在 src/migrations 目录下创建一个新的迁移文件。
编写迁移逻辑
import {MigrationInterface, QueryRunner} from "typeorm";
export class AddEmailToUser1632995728234 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" ADD "email" varchar NOT NULL`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "email"`);
}
}
应用迁移
typeorm migration:run
性能优化
为了提高应用性能,可以采取以下措施:
批量插入
const users = [
{ name: 'Alice', email: 'alice@example.com' },
{ name: 'Bob', email: 'bob@example.com' },
// ...
];
await userRepository.insert(users);
使用缓存
TypeORM 支持多种缓存策略,可以在一定程度上减少数据库访问次数。
import { Entity, Column, PrimaryGeneratedColumn, Cache } from 'typeorm';
@Entity()
@Cache()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
email: string;
}