上一章中用更新User的两个关联数据为例,介绍RelationQueryBuilder,今天把UserService里面全部用QueryBuilder改写,另外值得提的是这样做以后其实可以改注入entitymanager或是connection就可以了,两者的优劣就可能就是个人偏好或是大家可以讨论(应该是跟Performance有关吧!?)
注入Entitymanager
用QueryBuilder全部改写,意谓不会再用到TypeORM的Repository API,我们可以只注入EntityManager,习惯写SQL多一点的人适合。
修改user.service constructor部分
constructor(
// @InjectRepository(User) // 注入 typeorm repository
// private readonly userRepo: Repository<User>,
// 注入EntityManager可以指定Connection
// 会用default connection,多个connection要参考nestjs官网
@InjectEntityManager()
private readonly em: EntityManager,
private platformService: PlatformService,
private roleService: RoleService,
){}
user.module不用修改
这下关于userRepo的地方下面会有红色小蚯蚓,把useRep按F2 Refactor成em
还有一个要修改的地方是
// 会有红色小蚯蚓
this.em.createQueryBuilder('u')
// EntityManager必须要传入Entity Type
this.em.createQueryBuilder(User, 'u')
使用EntityManager的好处是可以使用Transaction,未来有机会再介绍,简单说可以实践多个SQL Operation在一个Transaction
Refactor getUserById
async getUserById(userId): Promise<User>{
// 载入roles导览属性
// 设定eager=true后要把plat拿掉,重复载入SQL语法错误
// return await this.userRepo.findOne(id, {relations: ['plat', 'roles']});
// return await this.userRepo.findOneOrFail(id); // 以id搜寻,沒找到会丟出例外
return await this.em
.createQueryBuilder(User, 'u')
.leftJoinAndSelect('u.roles', 'r')
.leftJoinAndSelect('u.plat', 'p')
.whereInIds(userId)
.select([
'u.id',
'u.name',
'u.age',
'p.id',
'p.platformname',
'r.id',
'r.roleName',
])
.getOne(); // 单笔使用getOne
}
Refactor addUser
async addUser(data: UserDTO): Promise<User>{
const user = new User();
user.name = data.name;
user.age = data.age;
// // user.platId = data.platId; 不能只指定id,必须传入platform对象save的时候才会储存关联资料
// user.dep = await this.depService.getDepById(data.depId);
// // 先要取得role,再指给user物件下的roles,save时才会存储关联
// user.roles = await this.roleService.getRolesByIds(data.roleIds);
// return await this.userRepo.save(user);
let userId;
await this.em.createQueryBuilder()
.insert() // 不接受任何参数
.into(User) //
.values(user) // 先更新关联以外的属性
.execute() // 必须execute才会产生SQL送到DB
.then(async (result) => {
Logger.log(result); // 到console看回传的格式
userId = result.identifiers[0].id; // 取得新增后回传的id
// 以下更新关联属性
await this.em.createQueryBuilder()
.relation(User, 'roles')
.of(userId)
.add(data.roleIds)
.then(async () => {
await this.em.createQueryBuilder()
.relation(User, 'plat')
.of(userId)
.set(data.platId);
});
});
return this.getUserById(userId);
}
Refactor deleteUser
async deleteUser(id){
const userDeleted = this.getUserById(id); // 先把原本的User存起來
return this.em.createQueryBuilder()
.delete()
.from(User)
.whereInIds(id) // 指定id for delete
.execute()
.then(result => userDeleted); // 回传raw沒有资料
}
cache
取得user list的时候可以使用cache(Repository API也有),以QueryBuilder改写getUsers
async getUsers(pageInfo: UserQueryDTO): Promise<User[]>{
return await this.em
.createQueryBuilder(User, 'u')
.leftJoinAndSelect('u.roles', 'r')
.leftJoinAndSelect('u.plat', 'p')
.select([
'u.id',
'u.name',
'u.age',
'p.id',
'p.platformname',
'r.id',
'r.roleName',
])
.orderBy('p.platformname', 'ASC')
.addOrderBy('u.name')
.skip((pageInfo.page - 1) * pageInfo.pageSize)
.take(pageInfo.pageSize) // 取pageSize
.cache(60000) // 1 min內
.getMany();
}
使用postman测试
TypeORM还有最后一个值得分享是Listener跟有关embedded entity,再来就回到nestjs
推荐一下我的公众号: 【 geekjc 】,微信号: 【 c8706288 】一起学习交流编程知识,分享经验,各种有趣的事。