TypeORM 是一个ORM框架,它可以运行在 NodeJS、Browser、Cordova、PhoneGap、Ionic、React Native、Expo 和 Electron 平台上,可以与 TypeScript 和 JavaScript (ES5,ES6,ES7,ES8)一起使用。
实体是一个映射到数据库表(或使用 MongoDB 时的集合)的类。 你可以通过定义一个新类来创建一个实体,并用@Entity()来标记:
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm";
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column()
isActive: boolean;
}
@PrimaryColumn() 创建一个主列,它可以获取任何类型的任何值。
@PrimaryGeneratedColumn() 创建一个主列,该值将使用自动增量值自动生成。
@PrimaryGeneratedColumn("uuid") 创建一个主列,该值将使用uuid自动生成。 Uuid 是一个独特的字符串 id。 你不必在保存之前手动分配其值,该值将自动生成。
使用带枚举值的数组:
export type UserRoleType = "admin" | "editor" | "ghost",
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({
type: "enum",
enum: ["admin", "editor", "ghost"],
default: "ghost"
})
role: UserRoleType
}
列选项定义实体列的其他选项,在@ Column上指定列选项
@Column({
type: "varchar",
length: 150,
unique: true,
// ...
})
name: string;
几个常用的列选项
type: ColumnType - 列类型。
name: string - 数据库表中的列名。
length: number - 列类型的长度。 例如,如果要创建varchar(150)类型
nullable: boolean - 在数据库中使列NULL或NOT NULL。 默认情况下,列是nullable:false
update: boolean - 指示"save"操作是否更新列值。如果为false,则只能在第一次插入对象时编写该值。 默认值为"true"
select: boolean - 定义在进行查询时是否默认隐藏此列。 设置为false时,列数据不会显示标准查询。 默认情况下,列是select:true
default: string - 添加数据库级列的DEFAULT值。
unique: boolean - 将列标记为唯一列(创建唯一约束)
comment: string - 数据库列备注,并非所有数据库类型都支持。
enum: string[]|AnyEnum - 在enum列类型中使用,以指定允许的枚举值列表。
int, tinyint, smallint, mediumint, bigint, float, double, dec, decimal, numeric, date, datetime, timestamp, time, year, char, varchar, nvarchar, text, tinytext, mediumtext, blob, longtext, tinyblob, mediumblob, longblob, enum, json, binary, geometry, point, linestring, polygon, multipoint, multilinestring, multipolygon, geometrycollection
const user = repository.create(); // 和 const user = new User();一样
const user = repository.create({
id: 1,
firstName: "Timber",
lastName: "Saw"
}); // 和const user = new User(); user.firstName = "Timber"; user.lastName = "Saw";一样
const user = new User();
repository.merge(user, { firstName: "Timber" }, { lastName: "Saw" }); // 和 user.firstName = "Timber"; user.lastName = "Saw";一样
await repository.save(user);
await repository.save([category1, category2, category3]);
await repository.remove(user);
await repository.remove([category1, category2, category3]);
await repository.insert({
firstName: "Timber",
lastName: "Timber"
});
await repository.update({ firstName: "Timber" }, { firstName: "Rizzrak" });
// 执行 UPDATE user SET firstName = Rizzrak WHERE firstName = Timber
await repository.update(1, { firstName: "Rizzrak" });
// 执行 UPDATE user SET firstName = Rizzrak WHERE id = 1
await repository.delete(1);
await repository.delete([1, 2, 3]);
await repository.delete({ firstName: "Timber" });
count - 符合指定条件的实体数量。对分页很有用。
const count = await repository.count({ firstName: "Timber" });
find - 查找指定条件的实体。
const timbers = await repository.find({ firstName: "Timber" });
const [timbers, timbersCount] = await repository.findAndCount({ firstName: "Timber" });
const users = await repository.findByIds([1, 2, 3]);
findOne - 查找匹配某些 ID 或查找选项的第一个实体。
const user = await repository.findOne(1);
const timber = await repository.findOne({ firstName: "Timber" });
userRepository.find({ select: ["firstName", "lastName"] });
userRepository.find({ where: { firstName: "Timber", lastName: "Saw" } });
userRepository.find({
order: {
name: "ASC",
id: "DESC"
}
});
userRepository.find({
skip: 5
});
userRepository.find({
take: 10
});
userRepository.find({
select: ["firstName", "lastName"],
relations: ["profile", "photos", "videos"],
where: {
firstName: "Timber",
lastName: "Saw"
},
order: {
name: "ASC",
id: "DESC"
},
skip: 5,
take: 10,
cache: true
});
为了与 SQL和 NoSQL 数据库集成,Nest 提供了 @nestjs/typeorm 包。Nest 使用TypeORM是因为它是 TypeScript 中最成熟的对象关系映射器( ORM )。因为它是用 TypeScript 编写的,所以可以很好地与 Nest 框架集成。
yarn add @nestjs/typeorm typeorm mysql2
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'mysql',
host: 'localhost',
port: 3306,
username: 'root',
password: 'kerry123',
database: 'db_cloud_collect',
// entities: [],
// 自动载入实体
autoLoadEntities: true,
// 默认:false,如果为true,自动载入的模型将同步,禁止生产环境使用,否则数据将会丢失
synchronize: true,
}),
],
})
export class AppModule {}
forRoot() 方法支持所有TypeORM包中createConnection()函数暴露出的配置属性。
使用 forRootAsync() 函数,异步传递模块选项,而不是事先传递它们
import { Module } from '@nestjs/common';
import { ConfigService, ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
@Module({
imports: [
ConfigModule.forRoot({
//全局使用,无需在其他模块中导入它
isGlobal: true,
// 自定义 env 文件路径,默认情况下,程序在应用程序的根目录中查找.env文件
envFilePath: ['.env'],
}),
// 异步配置
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
type: 'mysql',
host: configService.get('DB_HOST'),
port: configService.get('DB_PORT'),
username: configService.get('DB_USER'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_DATABASE'),
// entities: [__dirname + '/**/*.entity{.ts,.js}'],
autoLoadEntities: true,
synchronize: true,
}),
})
]
})
export class AppModule {}
将从默认位置(项目根目录)载入并解析一个.env文件,从.env文件拿到环境变量键值对,并将结果存储到一个可以通过ConfigService访问的私有结构。forRoot()方法注册了ConfigService提供者,后者提供了一个get()方法来读取这些解析/合并的配置变量。
我们在根目录下创建一个.env文件,添加一下键值对
DB_HOST=localhost
DB_PORT=3306
DB_USER=root
DB_PASSWORD=123434
DB_DATABASE=db_test
当然,要使用ConfigModule和ConfigService,我们需要先安装@nestjs/config,这是Nest 提供的一个开箱即用的包,创建一个 ConfigModule ,它暴露一个 ConfigService ,根据 $NODE_ENV 环境变量加载适当的 .env 文件。
yarn add @nestjs/config
在user.module.ts模块中导入TypeOrmModule.forFeature并对实体进行注册,这样,我们就可以使用 @InjectRepository()装饰器将 UsersRepository 注入到 UsersService 中
// user.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersService } from './users.service';
import { UsersController } from './users.controller';
import { User } from './user.entity';
@Module({
imports: [TypeOrmModule.forFeature([User])],
providers: [UsersService],
controllers: [UsersController],
})
export class UsersModule {}
// users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(User)
private usersRepository: Repository<User>
) {}
findAll(): Promise<User[]> {
return this.usersRepository.find();
}
findOne(id: string): Promise<User> {
return this.usersRepository.findOne(id);
}
async remove(id: string): Promise<void> {
await this.usersRepository.delete(id);
}
}
现在我们熟悉了typeorm的基本操作,并在项目中将typeorm框架集成了进来,下面我们来实现一个curd操作
在根目录下创建一个link文件夹,然后目录下创建以下文件:
link.module.ts
link.controller.ts
link.service.ts
link.entity.ts
// link.entity.ts
import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';
@Entity('tb_link')
export class LinkEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
name: string;
@Column()
url: string;
}
// link.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { CreateLinkDto } from './dto/create-link.dto';
import { UpdateLinkDto } from './dto/update-link.dto';
import { LinkEntity } from './link.entity';
@Injectable()
export class LinkService {
constructor(
@InjectRepository(LinkEntity)
private linksRepository: Repository<LinkEntity>,
) {}
async create(createLinkDto: CreateLinkDto) {
// this.linksRepository.create 相当于 const link = new LinkEntity();
const link = await this.linksRepository.create({
...createLinkDto,
});
// 保存给定实体或实体数组。如果该实体已存在于数据库中,则会更新该实体。如果数据库中不存在该实体,则会插入该实体。
const created = await this.linksRepository.save(link);
return created;
}
async findAll() {
return this.linksRepository.find();
}
async findOne(id: number) {
return await this.linksRepository.findOne({
where: {
id,
},
});
}
async update(id: number, updateLinkDto: UpdateLinkDto) {
const link = await this.linksRepository.findOne({
where: {
id,
},
});
// 合并实体
const newLink = this.linksRepository.merge(link, updateLinkDto);
return await this.linksRepository.save(newLink);
}
async remove(id: number) {
const link = await this.linksRepository.findOne({
where: {
id,
},
});
return await this.linksRepository.remove(link);
}
}
我们在LinkController中通过类构造函数注入LinkService,这样我就可以在controller中使用LinkService提供的方法了
// link.controller.ts
import {
Controller,
Get,
Post,
Body,
Patch,
Param,
Delete,
} from '@nestjs/common';
import { LinkService } from './link.service';
import { CreateLinkDto } from './dto/create-link.dto';
import { UpdateLinkDto } from './dto/update-link.dto';
@Controller('link')
export class LinkController {
constructor(private readonly linkService: LinkService) {}
@Post()
create(@Body() createLinkDto: CreateLinkDto) {
return this.linkService.create(createLinkDto);
}
@Get()
findAll() {
return this.linkService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.linkService.findOne(+id);
}
@Patch(':id')
update(@Param('id') id: string, @Body() updateLinkDto: UpdateLinkDto) {
return this.linkService.update(+id, updateLinkDto);
}
@Delete(':id')
remove(@Param('id') id: string) {
return this.linkService.remove(+id);
}
}
编写好controller和service后,将其注册到模块中
// link.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { LinkService } from './link.service';
import { LinkController } from './link.controller';
import { LinkEntity } from './link.entity';
@Module({
controllers: [LinkController],
providers: [LinkService],
// 使用forFeature方法进行实体注册,这样,我们就可以使用 @InjectRepository()装饰器将 UsersRepository 注入到 UsersService 中
imports: [TypeOrmModule.forFeature([LinkEntity])],
})
export class LinkModule {}
最后,将我们的LinkModule模块导入到根模块AppModule中
import { Module } from '@nestjs/common';
import { ConfigService, ConfigModule } from '@nestjs/config';
import { TypeOrmModule } from '@nestjs/typeorm';
import { AppController } from './app.controller';
import { AppService } from './app.service';
import { LinkModule } from './link/link.module';
@Module({
imports: [
ConfigModule.forRoot({
//全局使用,无需在其他模块中导入它
isGlobal: true,
// 自定义 env 文件路径,默认情况下,程序在应用程序的根目录中查找.env文件
envFilePath: ['.env'],
}),
// 异步配置
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: async (configService: ConfigService) => ({
type: 'mysql',
host: configService.get('DB_HOST'),
port: configService.get('DB_PORT'),
username: configService.get('DB_USER'),
password: configService.get('DB_PASSWORD'),
database: configService.get('DB_DATABASE'),
// entities: [__dirname + '/**/*.entity{.ts,.js}'],
// 自动载入实体
autoLoadEntities: true,
// 默认:false,如果为true,自动载入的模型将同步,禁止生产环境使用,否则数据将会丢失
synchronize: true,
}),
}),
LinkModule,
],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}
全部接口遵循restful风格
获取全部链接 get方法
http://localhost:3000/link
根据id获取链接 get方法
http://localhost:3000/link/
根据id删除链接 delete方法
http://localhost:3000/link/
添加链接 post方法
http://localhost:3000/link
{
"name": "带林这此111122222",
"url": "http://drqiat.tz/pqdnmyw"
}
{
"name": "带林这此111122222",
"url": "http://drqiat.tz/pqdnmyw"
}
代码已经上传到github中,欢迎大家star,持续更新,如有任何问题可以联系我v:sky201208(注明来意)
https://github.com/fozero/cloud-collect-nestjs
大家好,我是阿健Kerry,一个有趣且乐于分享的人,前小鹏汽车、货拉拉高级前端工程师,长期专注前端开发,如果你对前端&Node.js 学习进阶感兴趣的话(后续有计划也可以),可以关注我,加我微信【sky201208】,拉你进交流群一起交流、学习共同进步,群内氛围特别好,定期会组织技术分享~