跳转到主要内容

separating-entity-definition

分离实体定义

您可以在模型中直接使用装饰器定义实体及其列,但有些人更喜欢在单独的文件中定义实体及其列,这些文件在 TypeORM 中称为 "实体模式"。

简单的定义示例:

import { EntitySchema } from "typeorm"

export const CategoryEntity = new EntitySchema({
name: "category",
columns: {
id: {
type: Number,
primary: true,
generated: true,
},
name: {
type: String,
},
},
})

带有关系的示例:

import { EntitySchema } from "typeorm"

export const PostEntity = new EntitySchema({
name: "post",
columns: {
id: {
type: Number,
primary: true,
generated: true,
},
title: {
type: String,
},
text: {
type: String,
},
},
relations: {
categories: {
type: "many-to-many",
target: "category", // CategoryEntity
},
},
})

复杂的示例:

import { EntitySchema } from "typeorm"

export const PersonSchema = new EntitySchema({
name: "person",
columns: {
id: {
primary: true,
type: "int",
generated: "increment",
},
firstName: {
type: String,
length: 30,
},
lastName: {
type: String,
length: 50,
nullable: false,
},
age: {
type: Number,
nullable: false,
},
},
checks: [
{ expression: `"firstName" <> 'John' AND "lastName" <> 'Doe'` },
{ expression: `"age" > 18` },
],
indices: [
{
name: "IDX_TEST",
unique: true,
columns: ["firstName", "lastName"],
},
],
uniques: [
{
name: "UNIQUE_TEST",
columns: ["firstName", "lastName"],
},
],
})

如果您希望使实体类型安全,可以定义一个模型,并在模式定义中指定它:

import { EntitySchema } from "typeorm"

export interface Category {
id: number
name: string
}

export const CategoryEntity = new EntitySchema<Category>({
name: "category",
columns: {
id: {
type: Number,
primary: true,
generated: true,
},
name: {
type: String,
},
},
})

扩展模式

当使用 装饰器 方法时,可以将基本列扩展到抽象类中,然后简单地扩展该抽象类。 例如,您的 idcreatedAtupdatedAt 列可以在此类 BaseEntity 中定义。有关详细信息,请参见 具体表继承 上的文档。

使用 EntitySchema 方法时,这是不可能的。但是,您可以利用 Spread Operator (...)。

重新考虑上面的 Category 示例。您可能希望将基本列描述提取出来,并在其他模式中重复使用。可以按照以下方式完成:

import { EntitySchemaColumnOptions } from "typeorm"

export const BaseColumnSchemaPart = {
id: {
type: Number,
primary: true,
generated: true,
} as EntitySchemaColumnOptions,
createdAt: {
name: "created_at",
type: "timestamp with time zone",
createDate: true,
} as EntitySchemaColumnOptions,
updatedAt: {
name: "updated_at",
type: "timestamp with time zone",
updateDate: true,
} as EntitySchemaColumnOptions,
}

现在您可以在其他模式模型中使用 BaseColumnSchemaPart,如下所示:

export const CategoryEntity = new EntitySchema<Category>({
name: "category",
columns: {
...BaseColumnSchemaPart,
// CategoryEntity 现在具有定义的 id、createdAt、updatedAt 列!
// 此外,还定义了以下新字段
name: {
type: String,
},
},
})

您可以在模式模型中使用嵌入实体,如下所示:

export interface Name {
first: string
last: string
}

export const NameEntitySchema = new EntitySchema<Name>({
name: "name",
columns: {
first: {
type: "varchar",
},
last: {
type: "varchar",
},
},
})

export interface User {
id: string
name: Name
isActive: boolean
}

export const UserEntitySchema = new EntitySchema<User>({
name: "user",
columns: {
id: {
primary: true,
generated: "uuid",
type: "uuid",
},
isActive: {
type: "boolean",
},
},
embeddeds: {
name: {
schema: NameEntitySchema,
prefix: "name_",
},
},
})

请确保将 BaseColumnSchemaPart 中的 extended 列也添加到 Category 接口中(例如,通过 export interface Category extend BaseEntity)。

单表继承

为了使用单表继承

  1. 父类模式中添加inheritance选项,指定继承模式("STI")和鉴别器列,该列将在每行上存储子类的名称。
  2. 对于所有子类的模式,设置type: "entity-child"选项,并使用上述描述的扩展操作符语法扩展父类的列。
// entity.ts

export abstract class Base {
id!: number
type!: string
createdAt!: Date
updatedAt!: Date
}

export class A extends Base {
constructor(public a: boolean) {
super()
}
}

export class B extends Base {
constructor(public b: number) {
super()
}
}

export class C extends Base {
constructor(public c: string) {
super()
}
}
// schema.ts

const BaseSchema = new EntitySchema<Base>({
target: Base,
name: "Base",
columns: {
id: {
type: Number,
primary: true,
generated: "increment",
},
type: {
type: String,
},
createdAt: {
type: Date,
createDate: true,
},
updatedAt: {
type: Date,
updateDate: true,
},
},
// 新增:继承选项
inheritance: {
pattern: "STI",
column: "type",
},
})

const ASchema = new EntitySchema<A>({
target: A,
name: "A",
type: "entity-child",
columns: {
...BaseSchema.options.columns,
a: {
type: Boolean,
},
},
})

const BSchema = new EntitySchema<B>({
target: B,
name: "B",
type: "entity-child",
columns: {
...BaseSchema.options.columns,
b: {
type: Number,
},
},
})

const CSchema = new EntitySchema<C>({
target: C,
name: "C",
type: "entity-child",
columns: {
...BaseSchema.options.columns,
c: {
type: String,
},
},
})

使用模式查询或插入数据

当然,您可以像使用装饰器一样在存储库或实体管理器中使用定义的模式。考虑前面定义的 Category 示例(使用其 InterfaceCategoryEntity 模式)以获取一些数据或操作数据库。

// 请求数据
const categoryRepository = dataSource.getRepository<Category>(CategoryEntity)
const category = await categoryRepository.findOneBy({
id: 1,
}) // category 的类型已正确定义!

// 向数据库插入新的类别
const categoryDTO = {
// 注意,ID 是自动生成的;请参阅上面的模式
name: "new category",
}
const newCategory = await categoryRepository.save(categoryDTO)