MikroORM 类型安全指南:实体引用与类型安全访问

MikroORM 类型安全指南:实体引用与类型安全访问

mikro-orm mikro-orm/mikro-orm: 是一个基于 PHP 的轻量级 ORM 库,它支持多种数据库,包括 MySQL、SQLite、PostgreSQL 等。适合用于 PHP 应用程序的数据库操作和对象关系映射,特别是对于需要轻量级、高性能的 ORM 库的场景。特点是轻量级、高性能、支持多种数据库。 mikro-orm 项目地址: https://gitcode.com/gh_mirrors/mi/mikro-orm

引言

在现代ORM框架中,类型安全是一个非常重要的特性。MikroORM通过一系列精心设计的类型系统和包装器,为开发者提供了强大的类型安全保障。本文将深入探讨MikroORM中的类型安全机制,包括实体引用、Reference包装器、Loaded类型等核心概念。

实体引用与初始化状态

在MikroORM中,实体关系被映射为实体引用。这些引用是具有至少主键可用的实体实例,它们被存储在Identity Map中,确保从数据库获取相同文档时会得到相同的对象引用。

@ManyToOne(() => User)
author!: User; // 值始终是User实体的实例

检查与初始化实体

我们可以通过以下方式检查实体是否已初始化:

const user = em.getReference(User, 123);
console.log(wrap(user).isInitialized()); // false,它只是一个引用
console.log(user.name); // undefined

await wrap(user).init(); // 触发数据库查询
console.log(wrap(user).isInitialized()); // true
console.log(user.name); // 已定义

虽然isInitialized()方法可用于运行时检查,但手动检查实体状态可能会变得繁琐。MikroORM提供了更好的解决方案——Reference包装器。

Reference包装器

基本用法

当定义@ManyToOne@OneToOne属性时,TypeScript编译器会认为所需实体总是已加载。使用Reference包装器可以解决这个问题:

@Entity()
export class Article {
  @PrimaryKey()
  id!: number;

  @ManyToOne()
  author: Ref<User>;

  constructor(author: User) {
    this.author = ref(author);
  }
}

使用示例

const article1 = await em.findOne(Article, 1);
article1.author instanceof Reference; // true
article1.author.name; // 类型错误,没有name属性
article1.author.unwrap().name; // 不安全同步访问,未加载时为undefined

const article2 = await em.findOne(Article, 1, { populate: ['author'] });
article2.author.$.name; // 类型安全的同步访问

同步访问方法

Reference包装器提供了几个同步访问方法:

const article = await em.findOne(Article, 1);
console.log(article.author.getEntity()); // 错误:未初始化
console.log(await article.author.load('name')); // 先加载作者
console.log(article.author.getProperty('name')); // 已加载,安全访问

ScalarReference包装器

类似于Reference包装器,MikroORM还提供了ScalarReference包装器用于包装标量值:

@Property({ lazy: true, ref: true })
passwordHash!: Ref<string>;

使用示例:

const user = await em.findOne(User, 1);
const passwordHash = await user.passwordHash.load();

对于对象类型的标量属性,需要显式使用ScalarRef类型:

@Property({ type: 'json', nullable: true, lazy: true, ref: true })
reportParameters!: ScalarRef<ReportParameters | null>;

Loaded类型

MikroORM的查询方法返回的不是简单的实体类型,而是Loaded类型,它表示哪些关系已被加载:

// res1类型为Loaded<User, never>[]
const res1 = await em.find(User, {});

// res2类型为Loaded<User, 'identity' | 'friends'>[]
const res2 = await em.find(User, {}, { populate: ['identity', 'friends'] });

类型安全同步访问

Loaded类型添加了特殊的$符号,允许对已加载属性进行类型安全的同步访问:

const user = await em.findOneOrFail(User, 1, { populate: ['identity'] });
console.log(user.identity.$.email); // 类型安全的同步访问

在自定义方法中使用

可以在自定义方法中使用Loaded类型来要求某些关系必须被加载:

function checkIdentity(user: Loaded<User, 'identity'>) {
  if (!user.identity.$.email.includes('@')) {
    throw new Error(`无效的电子邮件格式`);
  }
}

严格部分加载

Loaded类型还支持部分加载提示(fields选项),返回类型将只允许访问选定的属性:

const article = await em.findOneOrFail(Article, 1, {
  fields: ['title', 'author.email'],
  populate: ['author'],
});

const title = article.title; // 允许
const publisher = article.publisher; // 类型错误,未选择
const email = article.author.email; // 允许
const name = article.author.name; // 类型错误,未选择

总结

MikroORM通过以下机制提供了强大的类型安全保障:

  1. Reference包装器:处理实体引用的延迟加载和类型安全访问
  2. ScalarReference:处理标量属性的延迟加载
  3. Loaded类型:精确描述查询返回的实体状态
  4. 严格部分加载:确保只访问明确请求的字段

这些特性共同构成了MikroORM强大的类型系统,帮助开发者在开发过程中捕获更多潜在错误,提高代码质量和开发效率。

mikro-orm mikro-orm/mikro-orm: 是一个基于 PHP 的轻量级 ORM 库,它支持多种数据库,包括 MySQL、SQLite、PostgreSQL 等。适合用于 PHP 应用程序的数据库操作和对象关系映射,特别是对于需要轻量级、高性能的 ORM 库的场景。特点是轻量级、高性能、支持多种数据库。 mikro-orm 项目地址: https://gitcode.com/gh_mirrors/mi/mikro-orm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

钱勃骅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值