TypeORM 是一个强大的 Node.js ORM 框架,支持多种数据库(如 MySQL、PostgreSQL、SQLite 等),并提供了 Repository 模式来简化数据操作。以下是 TypeORM Repository 的入门指南,涵盖核心概念、基本操作及高级用法。
一、核心概念
-
Repository 的作用
Repository 是 TypeORM 中用于操作特定实体的核心接口,封装了数据库的增删改查(CRUD)操作。每个实体(如
User
、Photo
)对应一个专属的 Repository,提供类型安全的方法调用。 -
Repository 与 EntityManager 的区别
- Repository :专注于单一实体,提供类型化的方法(如
find()
、save()
)。 - EntityManager :管理多个实体,适用于事务操作或跨实体操作。
推荐:优先使用 Repository,复杂事务时使用 EntityManager。
- Repository :专注于单一实体,提供类型化的方法(如
二、快速入门
1. 环境准备
-
安装依赖
bashnpm install typeorm reflect-metadata pg # 以 PostgreSQL 为例
-
配置数据源
在data-source.ts
中定义数据库连接:typescriptimport "reflect-metadata"; import { DataSource } from "typeorm"; import { User } from "./entity/User"; export const AppDataSource = new DataSource({ type: "postgres", host: "localhost", port: 5432, username: "root", password: "admin", database: "test", entities: [User], synchronize: true, // 自动同步实体到数据库表 });
2. 定义实体
创建 User
实体类,映射到数据库表:
typescript
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column({ default: 0 })
age: number;
}
3. 获取 Repository
通过 AppDataSource
获取 User
的 Repository:
typescript
import { AppDataSource } from "./data-source";
import { User } from "./entity/User";
async function main() {
await AppDataSource.initialize();
const userRepository = AppDataSource.getRepository(User);
// 后续操作...
}
main();
三、基本操作
1. 插入数据
-
单条插入
typescriptconst user = new User(); user.firstName = "Timber"; user.lastName = "Saw"; user.age = 25; await userRepository.save(user); // 插入新记录
-
批量插入
typescriptconst users = [ { firstName: "Alice", lastName: "Smith", age: 30 }, { firstName: "Bob", lastName: "Johnson", age: 28 }, ]; await userRepository.insert(users); // 直接插入对象数组
2. 查询数据
-
查询所有记录
typescriptconst allUsers = await userRepository.find(); console.log(allUsers);
-
条件查询
typescript// 按 ID 查询 const firstUser = await userRepository.findOneBy({ id: 1 }); // 多条件查询 const timber = await userRepository.findOneBy({ firstName: "Timber", lastName: "Saw", });
-
高级查询(FindOptions)
typescriptconst users = await userRepository.find({ select: ["firstName", "lastName"], // 只查询指定字段 where: { age: { gt: 20 } }, // 年龄大于 20 order: { age: "DESC" }, // 按年龄降序 skip: 0, // 跳过 0 条 take: 10, // 取 10 条 });
3. 更新数据
-
通过实体更新
typescriptconst user = await userRepository.findOneBy({ id: 1 }); if (user) { user.age = 26; await userRepository.save(user); // 更新记录 }
-
直接更新
typescriptawait userRepository.update( { id: 1 }, // 条件 { age: 26 } // 更新字段 );
4. 删除数据
-
通过实体删除
typescriptconst user = await userRepository.findOneBy({ id: 1 }); if (user) { await userRepository.remove(user); // 删除记录 }
-
直接删除
typescriptawait userRepository.delete({ id: 1 }); // 根据条件删除
四、高级用法
1. 关联查询
假设 User
与 Photo
是一对多关系:
typescript
@Entity()
export class Photo {
@PrimaryGeneratedColumn()
id: number;
@Column()
url: string;
@ManyToOne(() => User, (user) => user.photos)
user: User;
}
@Entity()
export class User {
// ...其他字段
@OneToMany(() => Photo, (photo) => photo.user)
photos: Photo[];
}
-
查询关联数据
typescriptconst userWithPhotos = await userRepository.find({ relations: ["photos"], // 加载关联的 photos where: { id: 1 }, });
2. 使用 QueryBuilder
QueryBuilder 提供更灵活的查询方式:
typescript
const users = await userRepository
.createQueryBuilder("user")
.select(["user.firstName", "user.lastName"])
.where("user.age > :age", { age: 20 })
.orderBy("user.age", "DESC")
.getMany();
3. 事务管理
使用 EntityManager
处理事务:
typescript
await AppDataSource.manager.transaction(async (transactionalEntityManager) => {
const user = new User();
user.firstName = "Transaction";
user.lastName = "User";
await transactionalEntityManager.save(user);
const photo = new Photo();
photo.url = "https://example.com/photo.jpg";
photo.user = user;
await transactionalEntityManager.save(photo);
});
五、最佳实践
-
使用 Repository 替代直接 SQL
Repository 提供了类型安全的方法,减少 SQL 注入风险。
-
合理使用 FindOptions
通过
find()
的select
、where
等选项优化查询性能。 -
事务处理
涉及多个实体的操作时,使用事务确保数据一致性。
-
分页查询
使用
skip
和take
实现分页,避免一次性加载大量数据。 -
缓存查询结果
对不常变的数据,启用查询缓存(
cache: true
)提升性能。