我有一个问题。随着
@EntityRepository
装饰器在 typeorm@^0.3.6
中被标记为已弃用,现在推荐的或 TypeScript 友好的方式来为 NestJS 中的实体创建自定义存储库?之前的自定义存储库看起来像这样:
// users.repository.ts
import { EntityRepository, Repository } from 'typeorm';
import { User } from './user.entity';
@EntityRepository(User)
export class UsersRepository extends Repository<User> {
async createUser(firstName: string, lastName: string): Promise<User> {
const user = this.create({
firstName,
lastName,
});
await this.save(user);
return user;
}
}
由于 NestJS 默认配置了 TypeScript 支持,因此我可以在这样的服务中调用
usersRepository.createUser()
,而不会出现问题:
// users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersRepository } from './users.repository';
@Injectable()
export class UsersService {
constructor(
@InjectRepository(UsersRepository)
private readonly usersRepository: UsersRepository,
) {}
async createUser(firstName: string, lastName: string): Promise<User> {
return this.usersRepository.createUser(firstName, lastName);
}
}
这就是模块导入自定义存储库的方式:
// users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersRepository } from './users.repository';
import { UsersService } from './users.service';
@Module({
imports: [TypeOrmModule.forFeature([UsersRepository])],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
我在这里提到 MongoDB 的原因是因为我尝试使用
[email protected]
,其中 @EntityRepository
仍然受支持,但当我尝试将其导入模块时收到错误,指出 Repository not found
或其他内容。请注意,如果我选择 postgresql
作为 TypeORM 中的数据库并进行与上述相同的更改,则不会出现此问题。因此我去检查最新版本却发现它已经被弃用了,我也没有在 NestJS 文档中找到任何示例。
我想我找到了一个解决方案,它允许调用自定义方法,但也允许调用继承的方法。似乎这个“问题”还不太受欢迎,但在 typeorm GitHub 线程中肯定有一些关于它的讨论:https://github.com/typeorm/typeorm/issues/9013
以下解决方案使用 MySQL 作为底层数据库驱动程序,但我认为它也适用于 MongoDB。
team.repository.ts
import {DataSource, Repository} from 'typeorm';
import {Injectable} from '@nestjs/common';
import {Team} from '@Domain/Team/Models/team.entity';
@Injectable()
export class TeamRepository extends Repository<Team>
{
constructor(private dataSource: DataSource)
{
super(Team, dataSource.createEntityManager());
}
/**
* Add a basic where clause to the query and return the first result.
*/
async firstWhere(column: string, value: string | number, operator = '='): Promise<Team | undefined>
{
return await this.createQueryBuilder()
.where(`Team.${column} ${operator} :value`, {value: value})
.getOne();
}
}
团队.service.ts
import {Injectable} from '@nestjs/common';
import {Team} from '@Domain/Team/Models/team.entity';
import {TeamRepository} from '@Domain/Team/Repositories/team.repository';
@Injectable()
export class TeamService
{
constructor(
private teamRepository: TeamRepository,
)
{
}
async create(): Promise<Team>
{
const team: Team = await this.teamRepository.firstWhere('id', 1);
return this.teamRepository.save(team);
}
}
team.module.ts
import {Module} from '@nestjs/common';
import {TeamService} from '@Domain/Team/Services/team.service';
import {TypeOrmModule} from '@nestjs/typeorm';
import {Team} from '@Domain/Team/Models/team.entity';
import {TeamRepository} from '@Domain/Team/Repositories/team.repository';
@Module({
imports: [TypeOrmModule.forFeature([Team])],
exports: [TeamService],
providers: [TeamService, TeamRepository],
})
export class TeamModule
{
}
您可以通过以下方式在
TypeORM
中为mongo创建自定义存储库:
users.repository.ts
这里您将使用
@EntityRepository
装饰器而不是使用 @Injectable
,并且对于注入,schema
将使用 MongoRepository
// users.repository.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { MongoRepository } from 'typeorm';
import { User } from './user.entity';
@Injectable()
export class UsersRepository {
constructor(
@InjectRepository(User)
private readonly usersRepository: MongoRepository<User>,
) {}
async createUser(firstName: string, lastName: string): Promise<User> {
const user = new User({
firstName,
lastName,
});
await this.usersRepository.save(user);
return user;
}
//write other helpful methods here(find, delete, etc...)
}
users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersRepository } from './users.repository';
@Injectable()
export class UsersService {
constructor(private readonly usersRepository: UsersRepository) {}
async createUser(firstName: string, lastName: string): Promise<User> {
return this.usersRepository.createUser(firstName, lastName);
}
}
users.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { UsersController } from './users.controller';
import { UsersRepository } from './users.repository';
import { UsersService } from './users.service';
import { User } from './user.entity';
import { UsersRepository } from './database/repository/UsersRepository';
@Module({
imports: [TypeOrmModule.forFeature([User])],
controllers: [UsersController],
providers: [UsersRepository, UsersService],
exports: [UsersService],
})
export class UsersModule {}
// task.entity.ts
import { Column, Entity, PrimaryGeneratedColumn } from 'typeorm';
@Entity()
export class Task {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
title: string;
@Column()
description: string;
}
// tasks.repository.ts
import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { Task } from './tast.entity';
@Injectable()
export class TasksRepository extends Repository<Task> {
constructor(dataSource: DataSource) {
super(Task, dataSource.createEntityManager());
}
}
//tasks.module.ts
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { TasksController } from './tasks.controller';
import { TasksService } from './tasks.service';
import { Task } from './tast.entity';
@Module({
imports: [TypeOrmModule.forFeature([Task])], // NOTICE: HERE
controllers: [TasksController], // NOTICE: HERE
providers: [TasksService],
})
export class TasksModule {}
@Injectable()
export class TasksService {
constructor(
@InjectRepository(Task) // NOTICE: here
private readonly tasksRepository: TasksRepository,
) {}
async getTaskById(id: string): Promise<Task> {
const task = this.tasksRepository.findOne({
where: {
id,
},
});
if (!task) {
throw new NotFoundException(`Task with id ${id} not found`);
}
return task;
}
}
我刚刚开发了一个解决这个问题的包,你可以看看。
// users.repository.ts
import { Repository } from 'typeorm';
import { EntityRepository } from 'nestjs-typeorm-custom-repository';
import { User } from './user.entity';
@EntityRepository(User)
export class UsersRepository extends Repository<User> {}
// users.service.ts
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from './user.entity';
import { UsersRepository } from './users.repository';
@Injectable()
export class UsersService {
constructor(
private readonly usersRepository: UsersRepository,
) {}
...
}
}
// users.module.ts
import { Module } from '@nestjs/common';
import { CustomRepositoryModule } from 'nestjs-typeorm-custom-repository';
import { UsersController } from './users.controller';
import { UsersRepository } from './users.repository';
import { UsersService } from './users.service';
@Module({
imports: [CustomRepositoryModule.forFeature([UsersRepository])],
controllers: [UsersController],
providers: [UsersService],
exports: [UsersService],
})
export class UsersModule {}
@deprecated — 使用 Repository.extend 函数创建自定义存储库
请这样写
export const UserRepository = dataSource.getRepository(User).extend({
findByName(firstName: string, lastName: string) {
return this.createQueryBuilder("user")
.where("user.firstName = :firstName", { firstName })
.andWhere("user.lastName = :lastName", { lastName })
.getMany()
},
})