除了昨天,今天把我在官網關於Query Builder會用的功能做介紹,主要是
今天另外以role name作為query 變數加上分頁
有三個變數,建立新的queryUserDTO
export class UserQueryDTO{
@IsString()
name: string;
@IsNumber()
page: number;
@IsNumber()
pageSize: number;
}
修改app.controller query部分
```javascript
queryByDepName(@Query() query: UserQueryDTO){
//return this.usersService.getUsersByDepName(query);
return this.usersService.getUsersByRoleName(query);
}
新增getUsersByRoleName於app.service.ts
async getUsersByRoleName(query: UserQueryDTO){
return await this.userRepo
.createQueryBuilder('u')
.leftJoinAndSelect('u.roles', 'r')
.leftJoinAndSelect('u.dep', 'd')
// 以roleName作為篩選條件
.where('r.roleName like :name', { name: `%${query.name.toLowerCase()}%`})
.orderBy('u.username', 'ASC')
// Orderby也可以串聯
.addOrderBy('u.email')
// 跳過筆數,第一頁就為0,第二頁跳過pageSize筆
.skip((query.page - 1) * query.pageSize)
.take(query.pageSize) // 取pageSize筆數
.getManyAndCount(); //回傳record 並 count筆數
}
使用Postman測試
有時候不想expose所有欄位,可以用select來篩選,當然也有object mapping的套件把部分欄位mapping到新的class上,但先就選擇部分欄位為例,假設只想要username, email, depName及roleName,其他如isActive則不需要
async getUsersByRoleName(query: UserQueryDTO){
return await this.userRepo
.createQueryBuilder('u')
...
.skip((query.page - 1) * query.pageSize)
.take(query.pageSize) // 取pageSize筆數
.select([ //第一直覺只要列舉要的欄位
'u.username',
'u.email',
'd.depName',
'r.roleName',
])
//.addSelect('u.password') // select 隱藏欄位
// debug
//.getSql();
.getManyAndCount(); //回傳record 並 count筆數
}
使用postman測試
錯誤訊息是找不到u_id,用getSql()來取得sql看哪裡有錯
SELECT "u"."username" AS "u_username", "r"."roleName" AS "r_roleName", "d"."depName" AS "d_depName" FROM "My_Users" "u" LEFT JOIN "my__users_roles_role" "u_r" ON "u_r"."myUsersId"="u"."id" LEFT JOIN "role" "r" ON "r"."id"="u_r"."roleId" LEFT JOIN "Departments" "d" ON "d"."id"="u"."depId" WHERE "r"."roleName" like $1 ORDER BY "u"."username" ASC, "u"."id" DESC
原因是沒有SELECT u.id,我以為Primary key的選擇,TypeORM會自動產生,但沒有,所以要自己加,或是直接select alias
async getUsersByRoleName(query: UserQueryDTO){
return await this.userRepo
.createQueryBuilder('u')
...
.skip((query.page - 1) * query.pageSize)
.take(query.pageSize) // 取pageSize筆數
.select([ //第一直覺只要列舉要的欄位
'u.id',
'u.username',
'd.id',
'd.depName',
'r', // 選alias就會包含id了,只是所有欄位都會選取
// 'r.id',
//'r.roleName',
])
//.addSelect('u.password') // select 隱藏欄位
// debug
//.getSql();
.getManyAndCount(); //回傳record 並 count筆數
}
使用postman測試
P.S.
try的過程也是會遇到額外錯誤,一直用getSQL()除錯,耗時XDDD
如果有一個欄位在大多數時候都不希望被select到,只有少數情況會用到,typeorm提供隱藏欄位的概念,在QueryBuilder中select entity或是Repository find預設不會被選到,則需要在欄位上設定,如User Entity的password欄位
新增password欄位
@Entity('My_Users') // 指定table name
export class User {
@PrimaryGeneratedColumn()
id: number;
...
@Column({
nullable:true, // 因為此欄位後來才加,不設定nullable無法新增此欄位
length: 100,
// 一般用repository.find不會出現此欄位
// 在QueryBuilder中select entity也不會出現
select: false,
})
password: string;
}
![](https://i.imgur.com/e9R4wK9.png)
修改query, select User Entity
async getUsersByRoleName(query: UserQueryDTO){
return await this.userRepo
.createQueryBuilder('u')
...
.skip((query.page - 1) * query.pageSize)
.take(query.pageSize) // 取pageSize筆數
.select([ //第一直覺只要列舉要的欄位
'u', //直接select entity
'd.id',
'd.depName',
'r', // 選alias就會包含id了,只是所有欄位都會選取
// 'r.id',
//'r.roleName',
])
// debug
//.getSql();
.getManyAndCount(); //回傳record 並 count筆數
}
用postman測試
User Entity所有欄位都出現,只有password欄位沒出現
修改query, 新增addSelect讓password出現
async getUsersByRoleName(query: UserQueryDTO){
return await this.userRepo
.createQueryBuilder('u')
...
.skip((query.page - 1) * query.pageSize)
.take(query.pageSize) // 取pageSize筆數
.select([ //第一直覺只要列舉要的欄位
'u', //直接select entity
'd.id',
'd.depName',
'r', // 選alias就會包含id了,只是所有欄位都會選取
// 'r.id',
//'r.roleName',
])
.addSelect('u.password') // select 隱藏欄位
// debug
//.getSql();
.getManyAndCount(); //回傳record 並 count筆數
}
使用postman測試
密碼欄位出現