TypeORM 官方给的文档中,多表查询时使用的是通过实体关系进行leftjoin查询,我们知道TypeORM实体关系实际上是通过mysql的外键实现的。在实际开发中,外键因为有诸多限制不被推荐使用,大部分的都是无关系的表连接。经过几天的查找资料和摸索,找到了两种查询的方法,总结一下,如果大家有其他好的方法,欢迎留言讨论。
定义实体类
User 实体
import { Entity, Column, PrimaryColumn } from 'typeorm';
@Entity()
export class User {
@PrimaryColumn()
id: string;
@Column()
nickname: string;
@Column()
gender: number;
@Column()
avatarUrl: string;
@Column()
language: string;
@Column()
country: string;
@Column()
province: string;
@Column()
city: string;
}
Role 实体类
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Role {
@PrimaryGeneratedColumn()
id: number;
@Column()
roleId: number;
@Column()
userId: string;
}
Role_dic 实体类
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Role_dic {
@PrimaryGeneratedColumn()
id: number;
@Column()
roleId: number;
@Column()
roleName: string;
}
表关系
user.id = role.userId role.roleId = role_dic.roleId
User service查询的两种方式
方法一
// 查询语句
let queryBuilder = this.connection.createQueryBuilder(User, 'user');
const user = await queryBuilder
.leftJoinAndSelect(Role, 'role', 'role.userId = user.id')
.leftJoinAndSelect(Role_dic, 'role_dic', 'role_dic.roleId = role.roleId')
.where("user.id = :id", { id: userId })
.select(`
user.id as id,
user.nickname as nickname,
user.gender as gender,
user.avatarUrl as avatarUrl,
user.language as language,
user.country as country,
user.province as province,
user.city as city,
role.roleId as roleId,
role_dic.roleName as roleName
`)
.getRawOne();
// 返回结果
{
"id": "1630404672291",
"nickname": "xiaoditian",
"gender": 1,
"avatarUrl": "mytouxiang",
"language": "cn",
"country": "china",
"province": "henan",
"city": "zhengzhou",
"roleId": 1,
"roleName": "管理员"
}
这种方法使用getRawOne获取到sql查询后的原始数据,因为TypeORM会用别名,所以这里用select对字段进行了重命名,这个写法需要对每个需要的字段名进行重命名,否则返回的字段名称会带上表名。
方法二
//查询语句
let queryBuilder = this.connection.createQueryBuilder(User, 'user');
const user = await queryBuilder
.leftJoinAndMapOne('user.role', Role, 'role', 'role.userId = user.id')
.leftJoinAndMapOne('role.roleDic', Role_dic, 'role_dic', 'role_dic.roleId = role.roleId')
.where("user.id = :id", { id: userId })
.getOne();
//返回结果
{
"id": "1630404672291",
"nickname": "xiaoditian",
"gender": 1,
"avatarUrl": "mytouxiang",
"language": "cn",
"country": "china",
"province": "henan",
"city": "zhengzhou",
"role": {
"id": 1,
"roleId": 1,
"userId": "1630404672291",
"roleDic": {
"id": 1,
"roleId": 1,
"roleName": "管理员"
}
}
}
第二种方法使用leftJoinAndMapOne作字段映射,如果一对多可以使用leftJoinAndMapMany。这样就不用挨个对字段重命名,但是可能存在嵌套较深的问题。
总结
以上是常用的两种表连接的方法,每个都有其优缺点,可以根据情况选择使用。两外附上这两种方法的出处:
1、https://juejin.cn/post/6916483483095449608
2、https://www.cnblogs.com/zzk96/p/11397223.html