我已经构建了一个使用单个 sqlite 数据库的 Nestjs+typeorm 后端。
现在我想在我的项目中使用多个 sqlite 数据库文件。所有数据库文件将完全相同。我想为用户提供一个属性,告诉我要使用哪个数据库。我可以在我的验证函数或其他任何地方从我的
@User()
对象获取此信息,但如何告诉 Nestjs/typeorm 使用特定的数据库文件?
目前我在
app.module.ts
内imports
中设置数据库,如下所示:
imports: [
...
TypeOrmModule.forRootAsync({
useFactory: () => {
return {
type: 'sqlite',
database: __dirname + '/db/database.db',
keepConnectionAlive: true,
entities: ['dist/**/entities/*.entity{.ts,.js}'],
migrations: ['dist/db/migrations/*{.ts,.js}'],
synchronize: true,
logging: false,
};
},
}),
...
]
但是我如何在函数中更改它呢?或者更好的是,使用控制器装饰器自动获取
user.table
并设置要使用的数据库。
编辑: 我发现 this github issues 其中一个用户问了同样的问题,但针对 mysql。我尝试复制第一个示例并更改我的代码:
app.modul.ts
保持不变,目前仅加载我的默认数据库。
我创建了一个
getDbConnection()
函数,它接受我的有效负载令牌并为该特定数据库创建或返回已建立的连接:
import { PayloadToken } from 'src/auth/models/token.model';
import { ConnectionOptions, createConnection, getConnection } from 'typeorm';
export const getDbConnection = async (user: PayloadToken) => {
user.db = 'new';
try {
return getConnection(user.db);
} catch (err) {
// err = no connection with that name was found.
}
const options: ConnectionOptions = {
name: user.db, // name will be 'new'
type: 'sqlite',
entities: ['dist/**/entities/*.entity{.ts,.js}'],
migrations: ['dist/db/migrations/*{.ts,.js}'],
database: __dirname + `/db/${user.db}.db`, // db file will be 'new.db'
synchronize: true,
logging: false,
}
console.log('New connection!');
return createConnection(options);
};
之后,我替换了一个在我的
player.service.ts
中找到单个玩家的函数:
来自:
return this.playerRepository.findOne(id);
致:
return (await getDbConnection(user)).manager.findOne(id);
但这将解决一个错误(UUID 是我要查询的 id):
[Nest] 12072 - 14.02.2024, 10:17:54 ERROR [ExceptionsHandler] No metadata for "9fd8b32f-b058-4c37-b099-ea0f67e17e83" was found.
EntityMetadataNotFoundError: No metadata for "9fd8b32f-b058-4c37-b099-ea0f67e17e83" was found.
at EntityMetadataNotFoundError.TypeORMError [as constructor] (C:\Users\Me\Desktop\myProject\Backend\TestVersion\src\error\TypeORMError.ts:7:9)
at new EntityMetadataNotFoundError (C:\Users\Me\Desktop\myProject\Backend\TestVersion\src\error\EntityMetadataNotFoundError.ts:7:9)
at Connection.getMetadata (C:\Users\Me\Desktop\myProject\Backend\TestVersion\src\connection\Connection.ts:345:19)
at EntityManager.<anonymous> (C:\Users\Me\Desktop\myProject\Backend\TestVersion\src\entity-manager\EntityManager.ts:810:42)
at step (C:\Users\Me\Desktop\myProject\Backend\TestVersion\node_modules\tslib\tslib.js:144:27)
at Object.next (C:\Users\Me\Desktop\myProject\Backend\TestVersion\node_modules\tslib\tslib.js:125:57)
at C:\Users\Me\Desktop\myProject\Backend\TestVersion\node_modules\tslib\tslib.js:118:75
at new Promise (<anonymous>)
at __awaiter (C:\Users\Me\Desktop\myProject\Backend\TestVersion\node_modules\tslib\tslib.js:114:16)
at EntityManager.findOne (C:\Users\Me\Desktop\myProject\Backend\TestVersion\node_modules\typeorm\entity-manager\EntityManager.js:524:38)
我认为这与
ConnectionOptions
内的路径错误有关,所以我尝试将它们更改为:
entities: [__dirname + '/../../**/entities/*.entity{.ts,.js}'],
migrations: [__dirname + '/../../db/migrations/*{.ts,.js}'],
database: __dirname + `/../../../db/${user.db}.db`,
因为我的
__dirname
是 rootDir/dist/src/db-management
这应该指向相同的位置,就像我从复制这些路径的 app.module.ts
运行它一样,但我仍然收到相同的错误消息。
我明白了。
我确实用代码创建了一个
dbManager.ts
:
import { PayloadToken } from 'src/auth/models/token.model';
import { ConnectionOptions, createConnection, EntityTarget, getConnection } from 'typeorm';
const getDbConnection = async (user: PayloadToken) => {
user.db = 'test';
try {
return getConnection(user.db);
} catch (err) {
// err = no connection with that name was found.
}
const options: ConnectionOptions = {
name: user.db,
type: 'sqlite',
entities: [__dirname + '/../../**/entities/*.entity{.ts,.js}'],
migrations: [__dirname + '/../../db/migrations/*{.ts,.js}'],
database: __dirname + `/../../../db/${user.db}.db`,
synchronize: true,
logging: false,
}
console.log(`New DB connection to ${user.db}!`);
return createConnection(options);
};
export async function getDbRepository<Entity>(user: PayloadToken, entity: EntityTarget<Entity>) {
return (await getDbConnection(user)).manager.getRepository(entity);
}
getDbConnection
函数将返回一个新的或已经建立的Connection
,名称为user.db
。
现在,无论我想不使用默认数据库,我都需要将存储库调用替换为
getDbRepository
中的新 dbMangert.ts
。
例如:
this.playerRepository.findOne(id);
将会
(await getDbRepository(user, Player)).findOne(id); // Player is the entity
这就是我目前的做法。如果有更好或更优化的方法请告诉我。