如何正确实施存储库适配器?
How to correct implement the Repository Adapter?
我开始学习如何基于 TypeScript 和 NestJS 构建简洁的架构。一切正常,直到我开始实施存储库适配器和控制器。主要问题是 API 方法和用例的 return 类型不兼容。
我们的想法是将实体和用例放在 核心 文件夹中,其中用例使用存储库适配器(通过 DI)。该适配器也实现了 core 文件夹中的存储库接口。
存储库适配器的实现包含在 app 中。 app 还包含 NestJS 实现、TypeOrm 实体等。但我也想为某些控制器使用存储库,例如 getAll query
。
!!!还有问题!!!
对于几乎每个命令,我都必须使用 Mappers
因为 TypeORM 实体和域实体是不兼容的类型。我认为如果我们将该数据传递给用例就可以了,因为我们需要将数据从 TypeOrm 形状转换为域形状。
但如果我只是在控制器中调用存储库适配器方法,我需要再次将数据映射回来...而且我不知道如何跳过不必要的步骤。
在我的想象中,只要调用app服务中的repository方法即可,仅此而已。
如果我跳过映射,那么所有数据属性都将具有前缀 _
(
可能有人遇到同样的问题?
//核心区
帐户实体(/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;
}
}
//应用区
存储库适配器:
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;
}
在清洁架构中,控制和数据流通常是这样的:控制器从视图(例如网络应用程序)获取请求并将其转换为请求模型,然后传递给用例。用例从请求模型中读取它应该计算的内容,并使用存储库与域实体交互以最终创建响应模型。然后将响应模型传递给演示者(可能与控制器相同class),后者将其转换为视图的响应。
控制器通常不与域实体甚至 ORM 类型交互。
查看我关于实施清洁架构的博客系列以了解更多详细信息:http://www.plainionist.net/Implementing-Clean-Architecture-Controller-Presenter/
我开始学习如何基于 TypeScript 和 NestJS 构建简洁的架构。一切正常,直到我开始实施存储库适配器和控制器。主要问题是 API 方法和用例的 return 类型不兼容。
我们的想法是将实体和用例放在 核心 文件夹中,其中用例使用存储库适配器(通过 DI)。该适配器也实现了 core 文件夹中的存储库接口。
存储库适配器的实现包含在 app 中。 app 还包含 NestJS 实现、TypeOrm 实体等。但我也想为某些控制器使用存储库,例如 getAll query
。
!!!还有问题!!!
对于几乎每个命令,我都必须使用 Mappers
因为 TypeORM 实体和域实体是不兼容的类型。我认为如果我们将该数据传递给用例就可以了,因为我们需要将数据从 TypeOrm 形状转换为域形状。
但如果我只是在控制器中调用存储库适配器方法,我需要再次将数据映射回来...而且我不知道如何跳过不必要的步骤。
在我的想象中,只要调用app服务中的repository方法即可,仅此而已。
如果我跳过映射,那么所有数据属性都将具有前缀 _
(
可能有人遇到同样的问题?
//核心区
帐户实体(/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;
}
}
//应用区
存储库适配器:
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;
}
在清洁架构中,控制和数据流通常是这样的:控制器从视图(例如网络应用程序)获取请求并将其转换为请求模型,然后传递给用例。用例从请求模型中读取它应该计算的内容,并使用存储库与域实体交互以最终创建响应模型。然后将响应模型传递给演示者(可能与控制器相同class),后者将其转换为视图的响应。
控制器通常不与域实体甚至 ORM 类型交互。
查看我关于实施清洁架构的博客系列以了解更多详细信息:http://www.plainionist.net/Implementing-Clean-Architecture-Controller-Presenter/