元数据提供程序
作为实体发现过程的一部分,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 enablecompilerOptions.declaration
in ourtsconfig.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.ts
或 app.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;
当我们在单个文件中定义多个实体(彼此之间具有循环依赖)时,可能会出现递归问题。在这种情况下,我们可能想要通过装饰器的
type
或entity
属性提供类型,并将 TS 属性类型设置为其他类型(如any
或object
)。¥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
orentity
attributes and set the TS property type to something else (likeany
orobject
).
可能需要其他类型
¥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.