问题描述
我想创建一种方法checkAddressEnterContestBefore
来检查某些要求。此功能需要连接到数据库(MysqL),但我无法注入存储库。
在这种情况下我该怎么办?
import { Contest } from '../models';
import { CONTEST_STATUS } from './constants';
import { ContestEntryRepository } from '../repositories';
import { inject } from '@loopback/core';
export function checkEnterContest(contest: Contest,address: string): boolean {
....
if (!checkAddressEnterContestBefore(contest,address)) return false;
...
return true;
}
export async function checkAddressEnterContestBefore(
@inject(ContestEntryRepository) contestEntryRepository: ContestEntryRepository,contest: Contest,address: string): Promise<boolean> {
const contestEntry = await contestEntryRepository.findOne({
where: {
and: [
{ contestId: contest.id },{ address: address }
]
}
});
return contestEntry == null
}
解决方法
依赖注入分为两个部分:
- 使用
@inject
装饰器装饰接收代码的依赖项,以指定要注入的内容 - 此类代码的调用者必须解决IoC容器中的依赖项
在您的代码段中,您正在修饰checkAddressEnterContestBefore
以便通过DI接收一些参数(这是上面列表中的第一项)。代码完全可以编译吗? AFAIK,装饰器不能应用于常规函数,只能应用于类成员(静态或实例级别)。
使用静态类方法的示例:
export class CheckAddressEnterContestBefore {
static async run(
@inject(ContestEntryRepository) contestEntryRepository: ContestEntryRepository,contest: Contest,address: string): Promise<boolean> {
const contestEntry = await contestEntryRepository.findOne({
where: {
and: [
{ contestId: contest.id },{ address: address }
]
}
});
return contestEntry == null
}
}
现在checkEnterContest
尚未实现依赖项注入/解析(上面列表中的第二项)。
LoopBack提供了一个辅助函数invokeMethod
,您可以使用该函数来调用具有依赖项注入的方法。您将需要当前的Context
对象作为从中获取依赖项的源。
import {invokeMethod} from '@loopback/core';
export function checkEnterContest(ctx: Context,address: string): boolean {
....
const checkResult = await invokeMethod(
CheckAddressEnterContestBefore,'run',// context for resolving dependencies
ctx,// additional (non-injected) arguments
[contest,address],);
if (!checkResult) return false;
...
return true;
}
就我个人而言,我认为它是一种反模式,可以从代码库内部的上下文中解析依赖关系。相反,我建议使用常规的函数/方法参数在代码库的不同部分之间传递依赖关系,并且仅在顶层(通常在控制器方法中)使用基于@inject
的依赖关系注入。
这将使您的代码更易于单独测试,因为每个函数都清楚了它需要的依赖项,并且如果您的测试未提供所有必需的依赖项,则编译器会在编译时警告您。当您从上下文中解析依赖项时,您将仅在运行时发现缺少的依赖项,而这些依赖项由于您的测试未在上下文中绑定它们而无法解决。
话虽如此,这就是我如何重写您的代码:
export function checkEnterContest(
contestEntryRepository: ContestEntryRepository,address: string
): boolean {
....
if (!checkAddressEnterContestBefore(contestEntryRepository,contest,address)) return false;
...
return true;
}
export async function checkAddressEnterContestBefore(
contestEntryRepository: ContestEntryRepository,address: string
): Promise<boolean> {
const contestEntry = await contestEntryRepository.findOne({
where: {
and: [
{ contestId: contest.id },{ address: address }
]
}
});
return contestEntry == null
}
根据您喜欢的代码结构方式,将checkEnterContest
和checkAddressEnterContestBefore
作为ContestEntryRepository
方法可能会更好。