实际学习NestJs并面对一个节省类型orOneToMany关系的问题。 假设我有两个模块ProjectsModule @ PlansModule
在计划和项目实体之间存在一个一对多关系
@Entity()
export class Project extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
...
@OneToMany(type => Plan, plan => plan.project, { eager: true })
plans: Plan[];
}
@Entity()
export class Plan extends BaseEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
...
@ManyToOne(type => Project, project => project.plans, { eager: false } )
project: Project;
@Column()
projectId: string;
}
在ProjectsModule中,我有一个使用以下方法的ProjectsService:
async getProjectById(
id: string,
user: User
): Promise<Project> {
const found = await this.projectRepository.findOne({ where: { id, ownerId: user.id } });
if(!found) {
throw new NotFoundException(`Project with ID "${id}" not found`)
}
return found;
}
我的问题是当我尝试保存新计划时。 我的PlansService会像这样
调用PlanRepository async createPlan(
createPlanDto: CreatePlanDto,
user: User
): Promise<Plan> {
return this.planRepository.createPlan(createPlanDto, user);
}
在PlanRepository上:
constructor(
@Inject(ProjectsService)
private projectsService: ProjectsService
) {
super();
}
async createPlan(
createPlanDto: CreatePlanDto,
user: User
): Promise<Plan> {
const { title, description, project } = createPlanDto;
const plan = new Plan();
const projectFound = await this.projectsService.getProjectById(project, user)
plan.title = title;
plan.description = description;
plan.status = PlanStatus.ENABLED;
plan.owner = user;
plan.project = project;
try {
await plan.save();
} catch (error) {
this.logger.error(`Failed to create a Plan for user "${user.email}". Data: ${JSON.stringify(createPlanDto)}`, error.stack);
throw new InternalServerErrorException();
}
delete plan.owner;
return plan;
}
尝试此操作时,向我的计划控制器发送POST请求时会抛出此错误:
TypeError: this.projectsService.getProjectById is not a function
并尝试
console.log('service', this.projectsService)
给我
service EntityManager {
repositories: [],
plainObjectToEntityTransformer: PlainObjectToNewEntityTransformer {},
connection: Connection {
我想我没有正确使用projectsService,但我不知道在哪里可能犯了错误。
在模块方面,我正在其模块中导出ProjectsService:
exports: [ProjectsService]
并将完整的ProjectsModule导入PlansModule:
imports: [
TypeOrmModule.forFeature([PlanRepository]),
AuthModule,
ProjectsModule
],
很长的帖子,很抱歉,请尝试详尽。
答案 0 :(得分:0)
import { Injectable, NotFoundException } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from '../auth/user.entity';
import { PlanRepository } from './plan.repository';
import { GetPlanFilterDto } from './dto/get-plan-filter.dto';
import { Plan } from './plan.entity';
import { CreatePlanDto } from './dto/create-plan.dto';
@Injectable()
export class PlansService {
constructor(
@InjectRepository(PlanRepository)
private planRepository: PlanRepository,
) {}
async getPlans(filterDto: GetPlanFilterDto, user: User): Promise<Plan[]> {
return this.planRepository.find({ ...filterDto, ownerId: user.id });
}
async getPlanById(id: string, user: User): Promise<Plan> {
return this.planRepository.findOne({
where: { id, ownerId: user.id },
});
}
async createPlan(createPlanDto: CreatePlanDto, user: User): Promise<Plan> {
const { project, ...data } = createPlanDto;
return this.planRepository
.create({
projectId: project,
ownerId: user.id,
...data,
})
.save();
}
}
此PlanService仅 使用存储库的内部方法,如果您在发生错误的情况下进行登录,则ExceptionFilter将是对此的合适选择:https://docs.nestjs.com/exception-filters。>
您可以使用拦截器来代替检查是否已找到计划:
import {
CallHandler,
ExecutionContext,
Injectable,
NestInterceptor,
NotFoundException,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
@Injectable()
export class PlanNotFoundInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
return next.handle().pipe(
map(plan => {
if (!plan) {
throw new NotFoundException("plan couldn't be found");
}
return plan;
}),
);
}
}
然后在您的getById
(控制器)上使用@UseInterceptor,这将使您的服务,数据访问,日志记录,验证等分离。
我已经简化了实现(对于Interceptor),您可能需要对其进行一些调整以适应您的确切需求。
yarn run v1.22.4
$ jest
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
ts-jest[versions] (WARN) Version 24.9.0 of jest installed has not been tested with ts-jest. If you're experiencing issues, consider using a supported version (>=25.0.0 <
26.0.0). Please do not report issues in ts-jest if you are using unsupported versions.
PASS src/auth/user.repository.spec.ts
PASS src/projects/projects.service.spec.ts
PASS src/auth/jwt.strategy.spec.ts
PASS src/auth/user.entity.spec.ts
Test Suites: 4 passed, 4 total
Tests: 18 passed, 18 total
Snapshots: 0 total
Time: 3.774s, estimated 4s
Ran all test suites.
Done in 4.58s.
我没有花很多时间来检查您的测试,但是所做的更改并未对单元测试进行任何重大更改(对于e2e不能说相同,个人不使用Cucumber.js)。 / p>
这个答案的目的不是为您提供所需的代码,而是可以用来解决紧密耦合的组件的抽象。
您还可以使用拦截器来验证请求,检查是否存在project
,检查是否存在,如果没有则中止并返回错误。再次将您的错误处理与控制器/服务/其他分离。
您还可以选择向请求中添加/添加内容,例如已验证的.user
或标头中的值。 (如果要通过Request对象将projectId发送到Controller中,可能会很有用。)