除了昨天,今天把我在官網關於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;
}

修改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測試
密碼欄位出現