Skip to main content
Version: 6.4

元数据提供程序

作为实体发现过程的一部分,MikroORM 使用所谓的 MetadataProvider 来获取有关我们实体属性的必要类型信息。

¥As part of entity discovery process, MikroORM uses so called MetadataProvider to get necessary type information about our entities' properties.

我们还可以通过扩展抽象 MetadataProvider 类来实现自定义元数据提供程序。

¥We can also implement custom metadata provider by extending abstract MetadataProvider class.

我们可以使用 3 个内置元数据提供程序:

¥There are 3 built-in metadata providers we can use:

TsMorphMetadataProvider

使用 TsMorphMetadataProvider,MikroORM 将使用 ts-morph 读取所有实体的 TypeScript 源文件,以便能够检测所有类型。多亏了这一点,定义类型就足以进行运行时验证。

¥With TsMorphMetadataProvider MikroORM will use ts-morph to read TypeScript source files of all entities to be able to detect all types. Thanks to this, defining the type is enough for runtime validation.

要使用它,请先安装 @mikro-orm/reflection 包。

¥To use it, first install the @mikro-orm/reflection package.

import { TsMorphMetadataProvider } from '@mikro-orm/reflection';

await MikroORM.init({
metadataProvider: TsMorphMetadataProvider,
// ...
});

如果我们使用基于文件夹的发现,我们应该通过 entities 指定编译实体的路径,以及通过 entitiesTs 指定这些实体的 TS 源文件的路径。当我们通过 ts-node 运行 ORM 时,后者将被自动使用,或者如果我们在配置中明确传递 preferTs: true。请注意,preferTs: true 不应成为生产配置的一部分。

¥If we use folder-based discovery, we should specify paths to the compiled entities via entities as well as paths to the TS source files of those entities via entitiesTs. When we run the ORM via ts-node, the latter will be used automatically, or if we explicitly pass preferTs: true in the config. Note that preferTs: true should not be part of production config.

通过 node 运行时,.d.ts 文件用于获取类型,因此我们需要在生产版本中发送它们。不再需要 TS 源文件(自 v4 起)。确保在我们的 tsconfig.json 中启用 compilerOptions.declaration

¥When running via node, .d.ts files are used to obtain the type, so we need to ship them in the production build. TS source files are no longer needed (since v4). Be sure to enable compilerOptions.declaration in our tsconfig.json.

发现过程结束后,所有 元数据将被缓存。默认情况下,FileCacheAdapter 将用于将缓存存储在 JSON 文件中的 ./temp 文件夹中。

¥After the discovery process ends, all metadata will be cached. By default, FileCacheAdapter will be used to store the cache inside ./temp folder in JSON files.

我们可以通过 CLI 命令 mikro-orm cache:generate 生成生产缓存。

¥We can generate production cache via CLI command mikro-orm cache:generate.

我们可以通过实现 CacheAdapter 接口来实现自定义缓存适配器。

¥We can implement custom cache adapter by implementing CacheAdapter interface.

ReflectMetadataProvider

ReflectMetadataProvider 使用 reflect-metadata 模块从 TypeScript 编译器导出的装饰器元数据中读取类型。

¥ReflectMetadataProvider uses reflect-metadata module to read the type from decorator metadata exported by TypeScript compiler.

我们需要安装 reflect-metadata 模块并将其导入到我们应用的引导脚本的顶部(例如 main.tsapp.ts)。

¥We will need to install reflect-metadata module and import at the top of our app's bootstrap script (e.g. main.ts or app.ts).

import 'reflect-metadata';

下一步是在我们的 tsconfig.json 中启用 emitDecoratorMetadata 标志。

¥Next step is to enable emitDecoratorMetadata flag in our tsconfig.json.

由于这种方法不会影响性能,因此元数据缓存并不是真正必要的。

¥As this approach does not have performance impact, metadata caching is not really necessary.

await MikroORM.init({
metadataProvider: ReflectMetadataProvider,
// ...
});

限制和要求

¥Limitations and requirements

虽然 TsMorphMetadataProvider 不会遭受以下任何问题,但它会带来性能损失(仅限于通过元数据缓存更改实体定义的情况),并且通常与其他编译器(如 webpack 或 babel)不兼容。它还要求你在编译的 .js 实体旁边部署 .d.ts 文件(有关此内容的更多信息,请参阅 部署部分)。

¥While TsMorphMetadataProvider do not suffer from any of the following problems, it brings a performance penalty (that can be limited only to cases where you change your entity definition via metadata caching) and is in general not compatible with other compilers like webpack or babel. It also requires you to deploy .d.ts files alongside your compiled .js entities (more about this in the deployment section).

显式类型

¥Explicit types

自 v6 起,只要可以在不传递任何构造函数参数的情况下实例化实体,就会根据运行时默认值自动推断类型。只要你让你的构造函数意识到这一点,此限制就不适用。

¥Since v6, the type is inferred automatically based on the runtime default value, as long as it is possible to instantiate the entity without passing any constructor arguments. As long as you keep your constructors aware of that, this limitation does not apply.

不支持类型推断,我们需要始终明确指定类型:

¥Type inference is not supported, we need to always explicitly specify the type:

@Property()
createdAt: Date = new Date();

集合属性和已识别引用

¥Collection properties and Identified references

我们需要在 @OneToMany@ManyToMany 装饰器中提供目标实体类型:

¥We need to provide target entity type in @OneToMany and @ManyToMany decorators:

@OneToMany(() => Book, b => b.author)
books = new Collection<Book>(this);

@ManyToOne(() => Publisher, { ref: true })
publisher!: Ref<Publisher>;

可选属性

¥Optional properties

不支持读取属性可空性,我们需要明确设置 nullable 属性:

¥Reading property nullability is not supported, we need to explicitly set nullable attribute:

@Property({ nullable: true })
prop?: string;

枚举

¥Enums

默认情况下,枚举被视为数字类型。对于字符串枚举,我们需要明确提供以下之一:

¥By default, enum is considered as numeric type. For string enums, we need to explicitly provide one of:

  • 对枚举的引用(这将迫使我们在定义实体之前定义枚举)

    ¥reference to the enum (which will force us to define the enum before defining the entity)

    @Enum(() => UserRole)
    role: UserRole;
  • 枚举的名称(如果它存在于同一个文件中)

    ¥name of the enum (if it is present in the same file)

    @Enum({ type: 'UserRole' })
    role: UserRole;
  • 枚举项列表

    ¥list of the enum items

    @Enum({ items: ['a', 'b', 'c'] })
    role: UserRole;

循环依赖

¥Circular dependencies

如果存在循环依赖,则读取 @ManyToOne@OneToOne 属性中引用实体的类型将失败。我们需要在装饰器中明确定义类型(最好通过 entity: () => ... 回调)。

¥Reading type of referenced entity in @ManyToOne and @OneToOne properties fails if there is circular dependency. We will need to explicitly define the type in the decorator (preferably via entity: () => ... callback).

@ManyToOne({ entity: () => Author })
author: Author;

当我们在单个文件中定义多个实体(彼此之间具有循环依赖)时,可能会出现递归问题。在这种情况下,我们可能想要通过装饰器的 typeentity 属性提供类型,并将 TS 属性类型设置为其他类型(如 anyobject)。

¥There can be recursion issues when we define multiple entities (with circular dependencies between each other) in single file. In that case, we might want to provide the type via decorator's type or entity attributes and set the TS property type to something else (like any or object).

可能需要其他类型

¥Additional typings might be required

我们可能必须安装其他类型,一个例子是在 MongoDB 中使用 ObjectId,这需要安装 @types/mongodb

¥We might have to install additional typings, one example is use of ObjectId in MongoDB, which requires @types/mongodb to be installed.

使用 EntitySchema

¥Using EntitySchema

或者,你可以使用 EntitySchema,它适用于仅 JavaScript 项目。

¥Alternatively, you can use EntitySchema instead, which is suitable for JavaScript only projects.

如果你想要拥有绝对控制权,也可以使用 EntitySchema.fromMetadata() 工厂方法。

¥If you want to have absolute control, you can also use EntitySchema.fromMetadata() factory method.

与 JavaScript 一起使用部分 中阅读有关它的更多信息。

¥Read more about it in Usage with JavaScript section.