- 作者:老汪软件技巧
- 发表时间:2024-09-15 15:01
- 浏览量:
前言
哈喽大家好!我是嘟老板,有经验的小伙伴应该知道,不同的业务实体间,通常会存在一些相同的字段,比如创建人、创建时间、更新人、更新时间等等,既然每个实体都有,能不能把他们统一维护起来,供每个实体复用呢?今天我们就来看看,基于 TypeORM 如何实现实体复用。
阅读本文您将收获:
了解什么是 TypeORM 实体,如何定义。了解如何使用嵌入和集成实现 TypeORM 实体复用。等等...实体简介(选读)
若您已对 TypeORM 有所了解,可略过。
实体是一个与数据库表或者 MongoDB 集合对应的类(class),是数据库表或集合在应用程序中的表示。
若要创建一个 TypeORM 实体,需先定义一个类,然后使用 注解来标记它。
例如:
@Entity()
class User {
name: string
tel: string
email: string
// ...
}
嵌入列
嵌入列是一种特殊的实体列,它可以接受一个定义了实体列的类,并将这些列合并到当前实体的数据库表中。
实现
嵌入列通过定义一个特殊的列,即可完成嵌入。例如:
@Column(() => Base)
base: Base
创建基础类
通常业务实体都会包含以下字段:
我们可以创建一个基础类 BaseEntity,专门维护公共的实体列。
import {
Column,
CreateDateColumn,
DeleteDateColumn,
UpdateDateColumn,
VersionColumn
} from 'typeorm'
import { BaseEntity as Base } from './base/base.entity'
export class BaseEntity {
// 数据版本
@VersionColumn()
version!: number
// 创建人
@Column()
createdBy!: string
// 创建时间
@CreateDateColumn()
createdAt!: Date
// 更新人
@Column()
updatedBy!: string
// 更新时间
@UpdateDateColumn()
updatedAt!: Date
// 删除时间
@DeleteDateColumn()
deletedAt!: Date
}
创建业务实体
假设现有一个菜单实体 Menu,我们将 BaseEntity 定义的列嵌入到 Menu 类中。
import { ACTIVATION_STATUS, MENU_TYPE, MENU_TYPE_DESC } from '@constants/enums'
import {
Column,
CreateDateColumn,
DeleteDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
VersionColumn
} from 'typeorm'
@Entity({ name: 'menu' })
export class Menu {
@PrimaryGeneratedColumn()
id!: number
// 菜单编码
@Column({ unique: true })
code!: string
// 菜单名称
@Column()
name!: string
// 其他列 ...
@Column(() => Base)
base: Base
}
这样 Menu 实体除去本身定义的业务列外,还会额外嵌入以下列:
细心的小伙伴会发现,嵌入到 Menu 类中的列名称并没有保持 BaseEntity 中定义的名称,而是按照命名规则: 目标实体类定义的列名称 + BaseEntity 定义的列名称,并转换为小驼峰形式 重新命名,例如 Menu 实体类定义的 base 拼接 BaseEntity 定义的 version、createdBy...
若您的程序中不想使用嵌入列的列命名规则,可以使用 实体继承,请继续往下看...
实体继承
实体继承分为以下两种方式:
我们分别来看一下...
具体表继承(推荐)
具体表继承是最简单且最有效的继承方法,属于一种数据库集成策略,会为每个业务类创建单独的数据表。
实现
上文中的 BaseEntity 基础类不变,调整下 Menu 实体类,干掉 Menu 类中嵌入的 base 字段,改为使用 extends 继承 BaseEntity 类。
import { ACTIVATION_STATUS, MENU_TYPE, MENU_TYPE_DESC } from '@constants/enums'
import {
Column,
CreateDateColumn,
DeleteDateColumn,
Entity,
PrimaryGeneratedColumn,
UpdateDateColumn,
VersionColumn
} from 'typeorm'
@Entity({ name: 'menu' })
export class Menu extends BaseEntity {
@PrimaryGeneratedColumn()
id!: number
// 菜单编码
@Column({ unique: true })
code!: string
// 菜单名称
@Column()
name!: string
// 其他列 ...
}
这样就完成了具体表继承,仅仅需要通过 extends 关键字继承基础类即可,确实十分的简单。
个人认为,这是最符合业务实体定义习惯的复用方式,基础类中定义的列会直接继承到业务实体类中,不会更改列名,而且会为目标实体创建包含继承列的数据表。
单表继承
同样是实体继承,单表继承有何不同呢?
当存在多个类,各自拥有不同的属性,但在数据库中,这些类的数据存储在同一个表中。这种情况可以用到单表继承。
实现
TypeORM 提供 @TableInheritance 注解来方便实现单表继承。
创建继承类
假设现有两个业务实体类:菜单实体 Mneu 和按钮实体 Button,它们存在公共属性:id、code、name。
新增一个 Resource 类,定义 Menu 类和 Button 类的公共属性:
import {
Entity
Column,
PrimaryGeneratedColumn,
TableInheritance
} from 'typeorm'
@Entity()
@TableInheritance({ column: { type: "varchar", name: "type" } })
export class Resource {
@PrimaryGeneratedColumn()
id: number
@Column()
code: string
@Column()
name: string
}
定义业务实体类
Menu 类和 Button 类定义如下,需要注意以下几点:
Menu 类:
import {
ChildEntity,
Column,
} from 'typeorm'
@ChildEntity()
export class Menu extends Resource {
@Column()
type: string
}
Button 类:
import {
ChildEntity,
Column,
} from 'typeorm'
@ChildEntity()
export class Button extends Resource {
@Column()
size: string
}
这样单表继承就搞定了,数据库中会创建一个名为 resource 的数据表,Menu 和 Button 的实体数据都会存在该表中。
结语
本文重点介绍了如何基于 TypeORM 实现实体复用,主要有三种方式,分别是嵌入列、具体表继承和单表继承,其中:
希望对您有所帮助!ZimuAdmin 对 TypeORM 有深入应用,欢迎 star。
如您对文章内容有任何疑问或想深入讨论,欢迎评论区留下您的问题和见解。
技术简而不凡,创新生生不息。我是 嘟老板,咱们下期再会。
往期干货