4

我在不使用 ORM 工具的情况下支持多个数据库。对于这个例子,我将展示一个 Postgres 和 MSSQL UserQueries的例子

在此处输入图像描述

我有一个接口IDataBase,多个数据库实现了这个接口。

@injectable()
export class MssqlDatabase implements IDatabase {
    public async connect(): Promise<void> {
    }

    public async disconnect(): Promise<void> {
    }
}

此外,我的IUserQueries界面定义了查询

export interface IUserQueries {
    fetchUsers(): Promise<QueryResult>;
}

QueryResult是一个自定义类,以确保每个数据库查询都为我的 API 返回相同的数据对象。我的 API 从目标接口调用特定查询。如果mssql是配置文件中的标识符,我的应用程序应该创建到 MSSQL 数据库的连接。但是我的 API 文件不应该关心并且不知道这一点(显然,这就是接口的作用)。

一个基本的例子是

@injectable()
export class UserRepository implements IUserRepository {
    public userQueries: IUserQueries;

    constructor(@inject(IoCTypes.IUserQueries) userQueries: IUserQueries) {
        this.userQueries = userQueries;
    }
}

现在事情变得棘手了。我的 DI 容器:

const container: Container = new Container();
container.bind<IUserQueries>(IoCTypes.IUserQueries).to(/* what? */);
export { container };

DI 容器不知道选择哪个查询文件。它可能是MSSQLUserQueriesor PostgresUserQueries。我怎么解决这个问题?启动服务器( app.ts )时可以选择正确的查询,但据我了解,这个 DI 容器完全独立于应用程序,只是充当配置文件,所以我不应该传入抽象UserQueries类.

4

2 回答 2

1

如果我理解正确,您的问题是关于在运行时选择某个接口 ( ) 的具体实现 ( MSSQLUserQueries, ) 之一- 基于某些配置。最简单的方法是使用工厂,它知道配置并返回正确的实现。PostgresUserQueriesIUserQueriesIUserQueries

container.bind<interfaces.Factory<IUserQueries>>(IoCTypes.IUserQueriesFactory).toFactory<IUserQueries>((context: interfaces.Context) => {
    return () => {
        const config = context.container.get('configuration');
        //if config.isPostgresql return PostgresUserQueries
        //if config.isMssql return MSSQLUserQueries
    };
});
于 2019-08-27T09:06:46.127 回答
1

您可以使用工厂模式:

interface IUserQueryFactory {
    get(): IUserQueries;
    get(type: string): IUserQueries;
}

class UserQueryFactory implements IUserQueryFactory {
    get(): IUserQueries {
        const defaultValue = config.database; // or whatever returns your "mssql" from config
        return this.get(defaultValue);
    }

    get(type: string): IUserQueries {
        switch (type) {
            case "mssql":
                return new MSSQLUserQueries();
            case "postgresql":
                return new PostgresUserQueries();
            default:
                return null;
        }
    }
}

const container: Container = new Container();
container.bind<IUserQueryFactory>(IoCTypes.IUserQueryFactory).to(UserQueryFactory);
container.bind<IUserQueries>(IoCTypes.IUserQueries).toDynamicValue((context: interfaces.Context) => { return context.container.get<IUserQueryFactory>(IoCTypes.IUserQueryFactory).get(); });
export { container };

我不确定我是否正确掌握了整个语法,因为这没有经过测试,但我想你明白了:

  1. IUserQueryFactoryIUserQueries如果类型不是提供者,则基于输入类型返回或返回默认值(在配置中定义的)
  2. 的默认实现IUserQueries基本上是通过它实现的,IUserQueryFactory这意味着整个创建源IUserQueries都在一个地方并且易于维护。
于 2019-08-27T09:36:55.363 回答