「这是我参与2022首次更文挑战的第20天,活动详情查看:2022首次更文挑战」
Active Record 与 Data Mapper
TypeORM中有两个模式: Active Record 和 Data Mapper,这两个模式的区别在于查询的方式。
Active Record
Active Record可以通过模型访问数据库:
const user = new User();
user.firstName = "Timber";
// 保存
await user.save();
// 删除
await user.remove();
// 查询
const users = await User.find({ skip: 2, take: 5 });
const timber = await User.findOne({ firstName: "Timber", lastName: "Saw" });
要使用Active Record,entity 必须要继承BaseEntity
import { BaseEntity, Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class User extends BaseEntity {
...
}
BaseEntity具有Repository中大部分的方法,无论是实例还是实体类,都可以方便地进行增删改查。如果需要增加自定义的增删改查方法,可以在实体类中增加一个静态方法,使用QueryBuilder:
@Entity()
export class User extends BaseEntity {
...
static findByName(firstName: string, lastName: string) {
return this.createQueryBuilder("user")
.where("user.firstName = :firstName", { firstName })
.andWhere("user.lastName = :lastName", { lastName })
.getMany();
}
}
const timber = await User.findByName("Timber", "Saw");
Data Mapper
Data Mapper模式下需要通过Repository进行增删改查,entity类不需要继承BaseEntity
// 获取Repository
const userRepository = connection.getRepository(User);
// 保存
const user = new User();
user.firstName = "Timber";
await userRepository.save(user);
// 删除
await userRepository.remove(user);
// 查询
const users = await userRepository.find({ skip: 2, take: 5 });
const timber = await userRepository.findOne({ firstName: "Timber", lastName: "Saw" });
如果需要扩展Repository,可以自定义一个类继承Repository:
import { EntityRepository, Repository } from "typeorm";
import { User } from "../entity/User";
@EntityRepository()
export class UserRepository extends Repository<User> {
findByName(firstName: string, lastName: string) {
return this.createQueryBuilder("user")
.where("user.firstName = :firstName", { firstName })
.andWhere("user.lastName = :lastName", { lastName })
.getMany();
}
}
const userRepository = connection.getCustomRepository(UserRepository);
const timber = await userRepository.findByName("Timber", "Saw");
使用QueryBuilder增删改查
QueryBuilder可以帮助我们以更便捷的方式构建SQL语句:
const firstUser = await connection
.getRepository(User)
.createQueryBuilder("user")
.where("user.id = :id", { id: 1 })
.getOne();
上面的代码可以返回一条user记录,相当于
SELECT
user.id as userId,
user.firstName as userFirstName,
user.lastName as userLastName
FROM users user
WHERE user.id = 1
创建QueryBuilder
可以使用connection、entity manager和repository创建QueryBuilder:
import { getConnection,getManager,getRepository } from "typeorm";
getConnection().createQueryBuilder()...
getManager().createQueryBuilder(User, "user")...
getRepository(User).createQueryBuilder("user")...
使用QueryBuilder
QueryBuilder实例具有增删改查方法,分别对应insert/delete/update/select
createQueryBuilder().insert().into(User).values([...])
createQueryBuilder().delete().from(User).where(...)
createQueryBuilder().update(User).set(...)
createQueryBuilder().select("user").from(User, "user")
QueryBuilder的常用api
- 别名
创建QueryBuilder可以传入一个参数:
createQueryBuilder("user"),这个参数表示对表设置别名user,之后where语句中可以使用该别名:.where("user.name = :name", { name: "Timber" }); - 表达式和参数 QueryBuilder支持多种表达式,如where,having,group by,order by,limit,offset:
createQueryBuilder("user").where("user.name = :name", { name: "Timber" });
createQueryBuilder("user").offset(10);
...
上面.where("user.name = :name", { name: "Timber" })等价于
.where("user.name = :name")
.setParameter("name", "Timber")
使用这种方式传参可以避免SQL注入。
- 联合查询
QueryBuilder支持联合查询,比如
createQueryBuilder("user").leftJoinAndSelect()