nestjs[一文学懂TypeORM在nestjs中的日常使用]
前提
第一步:需要先了解nestjs中使用typeorm的引入和使用。参考官方:TypeORM 集成
第二步:熟悉typeorm文档了解与熟悉相关的api内容基础。
学习步骤
1.了解nestjs中引入typeorm并且配置
引入相关库,参考前提-第一步
在真实的项目中往往数据库信息都是放在配置文件中。其中 Entities 代表着数据表实体集,往往好多学习文档中都会开启自动扫描autoLoadEntities 或者 synchronize 这种选项,但实际开发中不建议使用。直接自己建立表实体集统一管理即可。
// env.ts 环境配置文件
export default {env: 'development', // 环境// 数据库连接配置db: {name: 'default',host: 'localhost', // 数据库ip地址port: 3306, // 端口username: 'root', // 登录名password: '123456', // 密码},
}
// app.module.ts 文件
@Module({imports: [// 配置模块(必须)// ...ConfigModule引入与配置// 数据库配置TypeOrmModule.forRootAsync({imports: [ConfigModule],inject: [ConfigService],useFactory: (configService: ConfigService) => ({type: 'mysql', // 数据库类型host: configService.get('db.host'),port: configService.get('db.port'),username: configService.get('db.username'),password: configService.get('db.password'),name: configService.get('db.name'),entities: [...Entities], // 从entities文件中引入所有实体文件timezone: '+08:00', // 东八区}),}),]
})
2.建立实体类
在实际项目开发中,应根据数据库的表对应一一建立表实体类。有多少个表则建立多少个实体类,包括关联表或其他类型的表。统一实现管理
sys/index.ts示例
import { SysConfig } from './sys_config'
import { SysDept } from './sys_dept'
import { SysDictData } from './sys_dict_data'
import { SysDictType } from './sys_dict_type'
import { SysJob } from './sys_job'
import { SysLogininfor } from './sys_logininfor'
import { SysMenu } from './sys_menu'
import { SysRole } from './sys_role'
import { SysRoleDept } from './sys_role_dept'
import { SysRoleMenu } from './sys_role_menu'
import { SysUser } from './sys_user'
import { SysUserRole } from './sys_user_role'
import { SysUserWechat } from './sys_user_wechat'export * from './sys_config'
export * from './sys_dept'
export * from './sys_dict_data'
export * from './sys_dict_type'
export * from './sys_job'
export * from './sys_logininfor'
export * from './sys_menu'
export * from './sys_role'
export * from './sys_role_dept'
export * from './sys_role_menu'
export * from './sys_user'
export * from './sys_user_role'
export * from './sys_user_wechat'export const SysEntities = [SysConfig,SysDictData,SysDictType,SysJob,SysMenu,SysRole,SysRoleMenu,SysUser,SysUserWechat,SysUserRole,SysLogininfor,SysDept,SysRoleDept
]
index.ts示例:
import { SysEntities } from './sys'export * from './sys'export const Entities = [...SysEntities
]
实体类示例:
import { Column, Entity, Generated } from 'typeorm'
@Entity({ database: 'template-sys-center'})
export class SysConfig {@Column({type: 'int',name: 'config_id',comment: '参数主键',primary: true})@Generated('increment')configId: string@Column({type: 'varchar',length: 100,nullable: true,name: 'config_name',comment: '参数名称',default: ''})configName: string......
}
其中 database 表示库名,字段名与数据库字段名一一对应即可,使用@Column装饰器便能够满足字段的需要。其他的则按需使用。实体类设计简单与数据库表对应就够了,过度复杂的设计可能导致实体类管理与使用困难
tips: 关于typeorm其他的功能。如:一对多,多对多或者其他的辅助类装饰器,不在实体表中使用亦可。因为实际应用中仅仅知道单表的增删改查就足以满足绝大部分需要。极少特殊的可以特别处理。而剩余的其他各种需要均可在业务层进行操作。如:一对多,则开事务,多次按表按顺序查询返回即可。如:创建时间更新时间之类的则在业务层统一写个返回操作时间操作人的工具方法即可…
3.了解nestjs中typeorm引用
前面在项目启动时typeorm就已经连接并且准备完毕。之后只要按需使用即可
第一步:了解数据源、实体管理器、存储库
- 数据源 DataSource 保存你的数据库连接设置,并根据你使用的 RDBMS 建立初始数据库连接或连接池。
- 实体管理器使用 EntityManager,你可以管理(插入、更新、删除、加载等)任何实体。EntityManager 就像一个地方的所有实体存储库的集合。
- 存储库是实体管理器的具体实体。
第二步:了解@InjectDataSource(‘default’)、@InjectEntityManager(‘default’),@InjectRepository(ENTITY.SysDept, ‘default’),其中default参数其内容与TypeOrmModule.forRootAsync({name: ‘’})字段对应即可。默认是default。
应用示例:
使用数据源的情况还是非常少的。这种通常是应用与一些数据连接信息,数据库最基础的操作等内容。与实体类无关的操作。
@Injectable()
export class CodeGenerationService {constructor(@InjectDataSource('default') // 使用数据源(使用少)private dataSource: DataSource,) {}// 获取表列表async getList(tableName: string){const dbName = "'ry-vue-nestjs'";// 创建并执行最原始的sql语句操作,通常这种情况极少使用const list = await this.dataSource.query(`select table_name tableName,table_comment tableComment, create_time creatTime from information_schema.tables where table_schema = ${dbName}`,);}
}
实体管理器则是对整个实体集合的标识,因此如果需要使用操作某张表时,相关的方法前面必须设置对应的实体类。如:
// 使用 实体管理器
@Injectable()
export class AuthMapper {constructor(@InjectEntityManager('default')private entityManager: EntityManager, // 常用的方式,尤其是事务等,或者多表操作跨表操作) {}
}
存储库是对具体的某个实体类进行操作的标识,通常针对单表操作。如:
// xx.service.ts
@Injectable()
export class ConfigParamMapper {constructor(@InjectRepository(ENTITY.SysConfig, 'default')private useRepository: Repository<ENTITY.SysConfig>, // 常针对单表操作,需指定为哪个表的实体){}
}
// xx.module.ts
@Module({imports: [TypeOrmModule.forFeature([SysConfig])],providers: [ConfigParamMapper],controllers: [],
})
export class ConfigParamModule {}
4.关于实体管理器和存储库的使用
在官网上有实体管理器api和存储库api。但仔细一看,会发现两者有许多一样的方法。因此总结下使用方式
- 单表增删查改操作比较多的就用存储库形式,其余的都可以用实体管理器方式操作
- 关于api使用,须知api方法只是简化操作形式。如果会使用则更加方便开发,但如果不会使用也没有任何影响。直接全部使用查询构建器操作就行。
常用的实体管理器和存储库的api整理:(更多操作方式可从文档获取
.transaction() // 提供一个事务(仅实体管理器有
.createQueryBuilder() // 创建一个查询构建器用于构建 SQL 查询
.delete() // 按实体 id、ids 或给定条件删除实体,与remove相比,这个更好用
.find() // 查找与给定 FindOptions 匹配的所有实体。
.findOne() // 查找与给定 FindOptions 匹配的第一个实体
// 实体操作方法
.create(xx) // 创建xx实体类的新实例。如:const user = new User();
.save(xx) // 保存给定的实体或实体数组。如果该实体已存在于数据库中,则会对其进行更新。如果数据库中尚不存在该实体,则会将其插入。它将所有给定实体保存在单个事务中(在实体管理器不是事务性的情况下)。还支持部分更新,因为所有未定义的属性都会被跳过。为了使值 NULL,你必须手动将该属性设置为等于 null。
.remove() // 删除给定的实体或实体数组。它在单个事务中删除所有给定实体(在实体的情况下,管理器不是事务性的)。
.insert() // 插入一个新实体或实体数组
.update() // 通过给定的更新选项或实体 ID 部分更新实体。
5.常用增删改查操作
-增
.save() // 使用存储库或者实体管理器的.save方法
.insert() // 使用存储库或者实体管理器的.inset方法
.createQueryBuilder().insert().into(User).values([{ firstName: "Timber", lastName: "Saw" },{ firstName: "Phantom", lastName: "Lancer" },]).execute() // 使用查询构建器
-改
.save() // 使用存储库或者实体管理器的.save方法
.update() // 使用存储库或者实体管理器的.update方法
.createQueryBuilder().update(User).set({ firstName: "Timber", lastName: "Saw" }).where("id = :id", { id: 1 }).execute() // 使用查询构建器
-删
.delete() // 使用存储库或者实体管理器的.delete方法(常用)
.remove() // 使用存储库或者实体管理器的.remove方法
.createQueryBuilder().delete().from(User).where("id = :id", { id: 1 }).execute() // 使用查询构建器
-查
.find() // 使用存储库或者实体管理器的.save方法
.findOne() // 使用存储库或者实体管理器的.update方法
.createQueryBuilder("user").where("user.id = :id", { id: 1 }).getOne()
// 使用查询构建器
查询是一个非常大的分类,需要了解很多必要的知识和传递的参数参考:查找选项 和 使用查询构建器选择
关于事务
事务的使用很简单,从实体管理器创建即可。参考:事务
entityManager.transaction(async (managerEntity) => {managerEntity.save(xx,{}) // managerEntity 可以理解为特殊实体管理器managerEntity.remove(xx,{})
})
关于索引
必要的实体类字段添加索引能使搜索速度加快,提高性能。因此有必要了解。参考:索引
关于缓存、关系、特殊实体
关系可用可不用(一对一,一对多,多对多,懒惰等),没太大必要
缓存则根据需要进行使用,通常不需要管
树实体、视图实体之类的也是如此,可用可不用,没太大必要
关于查询构建器
通常来说,查询构建器可以构建出任何想要执行的sql操作,因此遇事不绝就直接查询构建器走起即可。参考:查询构建器
总结
了解上述相关内容即可满足typeorm的日常使用了,非特殊需要无需再去了解更多。
推荐一个nestjs项目
该项目基于知名的项目RuoYi-Vue项目进行改造而成。可方便参考开发
前端使用vue3、uniapp等开发框架。
后端使用nestjs
地址:https://gitee.com/twang-gitee/ry-vue-nestjs