如何正确实现存储库适配器?



我开始学习如何基于TypeScript和NestJS构建Clean Architecture。一切都很好,直到我开始实现存储库适配器和控制器。主要问题是API方法和用例的返回类型不兼容。

这个想法是把实体和用例放在核心文件夹,其中用例使用存储库适配器(通过DI)。这个适配器从核心

实现存储库接口。文件夹。app中存储库适配器的实现。应用还包含了NestJS实现,TypeOrm实体等。但是我也想为一些控制器使用一个存储库,比如getAll query

! !问题是!!

对于几乎每个命令,我都必须使用Mappers,因为TypeORM实体和Domain实体是不兼容的类型。我认为如果我们把数据传递给用例是可以的因为我们需要把数据从TypeOrm形状转换为域形状。

但是如果我只是在控制器中调用存储库适配器方法,我需要再次映射数据…我不知道怎么跳过不必要的步骤。在我的想象中,我可以调用app中的repository方法服务,仅此而已。如果我跳过映射那么所有的数据属性都有前缀_(

)也许有人遇到了同样的问题?

核心区域//

Account entity (/domain/account):

export type AccountId = string;
export class Account {
constructor(
private readonly _id: AccountId,
private readonly _firstName: string
) {}
get id(): AccountId {
return this._id;
}
get firstName() {
return this._firstName;
}
}

存储库接口(repositories/account-repository):

import { Account } from '../domains/account';
export interface AccountRepository {
getAccountById(id: string): Promise<Account>;
getAllAccounts(): Promise<Account[]>;
}

带有存储库的用例示例:

import { AccountRepository } from '../../repositories/account-repository';
export class ToDoSomething {
constructor(private readonly _accountRepository: AccountRepository) {}
async doSomethingWithAccount(command): Promise<boolean> {
const account = await this._accountRepository.getAccountById(
command.accountId,
);
if (!account) {
return false;
}
return true;
}
}

//APP区

库适配器:

import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Account } from '../../../../core/domains/account';
import { AccountRepository } from '../../../../core/repositories/account-repository';
import { AccountEntity } from '../account.entity';
import { AccountMapper } from '../account.mapper';
@Injectable()
export class AccountRepositoryAdapter implements AccountRepository {
constructor(
@InjectRepository(AccountEntity)
private readonly _accountRepository: Repository<AccountEntity>,
) {}
async getAccountById(id: string): Promise<Account> {
return this._accountRepository.findOne({ id: id });
// will return { id: 1, firstName: "name" }
// and because I need to use MapToDomain
}
async getAllAccounts(): Promise<Account[]> {
return this._accountRepository.find();
// Here too I need to use MapToDomain for every item
}
}

TypeOrm帐户:

import {
Column,
Entity,
PrimaryGeneratedColumn,
} from 'typeorm';
@Entity({ name: 'account' })
export class AccountEntity {
@PrimaryGeneratedColumn()
id: string;
@Column()
firstName: string;
}

在Clean Architecture中,控件和数据流通常是这样的:控制器接受来自视图(例如web应用程序)的请求,并将其转换为请求模型,然后传递给用例。用例从请求模型中读取它应该计算的内容,并使用存储库与域实体进行交互,最终创建响应模型。然后将响应模型传递给presenter(可能与controller是同一个类),后者将其转换为视图的响应。

控制器通常不与域实体甚至ORM类型交互。

查看我的博客系列关于实现Clean Architecture的更多细节:http://www.plainionist.net/Implementing-Clean-Architecture-Controller-Presenter/

最新更新