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,
},
},
})
扩展模式
当使用 装饰器
方法时,可以将基本列扩展到抽象类中,然后简单地扩展该抽象类。
例如,您的 id
、createdAt
和 updatedAt
列可以在此类 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
)。
单表继承
为了使用单表继承:
- 在父类模式中添加
inheritance
选项,指定继承模式("STI")和鉴别器列,该列将在每行上存储子类的名称。 - 对于所有子类的模式,设置
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
示例(使用其 Interface
和 CategoryEntity
模式)以获取一些数据或操作数据库。
// 请求数据
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)