简述
typeorm是一个数据库orm
框架,在nestjs
官网中有提到,可以充分发挥利用typescript
的特性,当然也支持js
其中涉及的概念包括
- DataSource 数据源,Connection 连接数据库
- Entity 实体,实体类映射数据库表
- Relation 关系,定义实体类之间的关系,也就是数据库表之间的关系,一对一,多对一,多对多。
- Entity Manager和Repository,Entity Manager可以管理创建连接时配置的所有实体,而Repository只能操作对应的实体,两个的api几乎的差不多的
- QueryBuilder,用来创建更复杂的sql查询,灵活度比较高。
使用typeorm cli快速创建项目
全局安装typeorm
typeorm cli的相关命令,可以快速测试初始化项目,生成实体等等
npm install typeorm -g
初始化项目
typeorm init --name MyProject
安装连接数据库驱动包,这里以msyql为2,安装msyql2
npm install mysql2
创建连接
import "reflect-metadata"
import { DataSource } from "typeorm"export const AppDataSource = new DataSource({type: "mysql",host: "localhost",port: 3306,username: "root",password: "zhuang",database: "typeorm_test",// 连接的数据库synchronize: true,// 开发过程使用,可以同步修改表结构,生产切忌使用。logging: true,// 打印输出sql语句connectorPackage: "mysql2",// 驱动包entities: ["./**/entity/*.ts"],// 指定entity文件,也可以是实体数组,[User]migrations: [],subscribers: []
})
定义实体Entity
使用typeorm的装饰器定义实体
装饰器列表
快速成实体
typeorm entity:create -n User
typeorm entity:create src/entity/HelloWorld # 快速生成实体类
实体装饰器
- @Entity(),@Entity({name:“指定表名”}) ,声明该类是实体类,对应表,表名默认是类名 Class 的小写下划线分割。
@Entity()
@Entity("user")
@Entity({name: "users",// 表名engine: "MyISAM", // 数据库引擎database: 'example_dev',// 数据库synchronize: false,// 是否同步更该表结构orderBy: {// 查询时的默认排序name: "ASC",id: "DESC"}
})
- @ViewEntity(),视图实体,不会对应表
@ViewEntity({ expression: `SELECT "post"."id" "id", "post"."name" AS "name", "category"."name" AS "categoryName"FROM "post" "post"LEFT JOIN "category" "category" ON "post"."categoryId" = "category"."id"`
})
export class PostCategory {}
列装饰器
- @Column(),用来定义实体对应表列,默认对应的列名就是实体的属性名,可以配置,属性的数据类型没有显示指定的话,typeorm会根据ts的类型自动推断,在
mysql
中,string - varchar(255), boolean - tinyint, number - int,Date - datetime(6)
- @PrimaryGeneratedColumn(), 相当于
@Column({primary:true})
具体的列装饰器都是固定了一些配置的装饰器. - @CreateDateColumn(),自动插入
- @UpdateDateColumn(),自动更新
@Entity("users")
export class User {@Column({ primary: true }) // 配置主键, @PrimaryGeneratedColumn("uuid"),配置uuid主键id: number;@Column({ type: "varchar", length: 200, unique: true })// 配置数据库中具体类型,长度,唯一firstName: string;@Column({ nullable: true })// 配置是否为空lastName: string;@Column({ default: false })// 配置默认值,boolen默认类型被转换为 tinyint, false 对应 0,true 对应 1isActive: boolean;@CreateDateColumn() // 创建时自动插入createdDate: Date;@UpdateDateColumn() // 更新时自动更新updatedDate: Date;}
关系装饰器
指定表之间的关系,默认配置会生成物理外键,可以通过配置RelationOptions
中{createForeignKeyConstraints:false}
,不生成外键约束。一般该配置位于装饰器的最后一个参数,如下配置:
/*** 描述表之间关系的配置*/
export interface RelationOptions {/*** 配置不同表之间插入或更新时,相关的对象怎么配置,cascade:true 表示级联,如 user.roles, 当save的时候,把关联的roles实体也保存或者更新* If set to true then it means that related object can be allowed to be inserted or updated in the database.* You can separately restrict cascades to insertion or updation using following syntax:** cascade: ["insert", "update", "remove", "soft-remove", "recover"] // include or exclude one of them*/cascade?: boolean | ("insert" | "update" | "remove" | "soft-remove" | "recover")[];/*** Indicates if relation column value can be nullable or not.*/nullable?: boolean;/*** 配置外键的onDelete* Database cascade action on delete.*/onDelete?: OnDeleteType;/*** 配置外键的onUpdate* Database cascade action on update.*/onUpdate?: OnUpdateType;/*** Indicate if foreign key constraints can be deferred.*/deferrable?: DeferrableType;/*** Indicates whether foreign key constraints will be created for join columns.* Can be used only for many-to-one and owner one-to-one relations.* Defaults to true.* 创建外键,默认是true */createForeignKeyConstraints?: boolean;/*** Set this relation to be lazy. Note: lazy relations are promises. When you call them they return promise* which resolve relation result then. If your property's type is Promise then this relation is set to lazy automatically.*/lazy?: boolean;/*** Set this relation to be eager.* Eager relations are always loaded automatically when relation's owner entity is loaded using find* methods.* Only using QueryBuilder prevents loading eager relations.* Eager flag cannot be set from both sides of relation - you can eager load only one side of the relationship.*/eager?: boolean;/*** Indicates if persistence is enabled for the relation.* By default its enabled, but if you want to avoid any changes in the relation to be reflected in the database you can disable it.* If its disabled you can only change a relation from inverse side of a relation or using relation query builder functionality.* This is useful for performance optimization since its disabling avoid multiple extra queries during entity save.*/persistence?: boolean;/*** When a parent is saved (with cascading but) without a child row that still exists in database, this will control what shall happen to them.* delete will remove these rows from database.* nullify will remove the relation key.* disable will keep the relation intact. Removal of related item is only possible through its own repo.*/orphanedRowAction?: "nullify" | "delete" | "soft-delete" | "disable";
}
- OneToOne(),拥有该列的是从表,拥有关系的一方,即拥有xxxId的一方必须和@JoinColumn()配合使用。第一个参数是一个函数,返回关联的实体类,第二个参数如果有,是指定关系的反方,即关联字段的那方的实体类可以通过它的xxx属性来查询关系,第三个参数是配置关系的选项,包括
cascade
级联,createForeignKeyConstraints
创建外键,eager
查询时总是把关系类也查出来。其他的关系装饰器也大抵如此。
cascade:true只能有一方配置
,如果两边都配置cascade:true
会报错,如果两边都配置,只要有一边不要配置cascade:[“remove”]就行。如果没有cascade:true
关系,那么保存实体时,关联的实体必须先保存到数据库中,否则报错。
报错信息如下
:
@Entity()
export class User {// 指定关联实体,假如Profile实体通过@OnetoOne() 声明 user:User 字段,那么查询profile时也可以查询到user类@OneToOne(type => Profile, profile => profile.user,{createForeignKeyConstraints:false// 不创建外键})@JoinColumn() // 表示user表有profileId字段关联 profile 表,profile: Profile;
}
- ManyToOne(),拥有该列的表是从表,默认生成关联id,多对一的情况下,可以省略 @JointColumn(), 除非想指定 关联id 和关联列
- OneToMany(),反向关系,用在一的一方
@Entity()
export class Photo {@PrimaryGeneratedColumn()id: number;@Column()url: string;// 第二个参数指定另一面关系的关联属性,这里可以省略 @JoinColumn(),默认生成字段 userId @ManyToOne(() => User, user => user.photos) user: User;
}@Entity()
export class User {@PrimaryGeneratedColumn()id: number;@Column()name: string;@OneToMany(() => Photo, photo => photo.user) photos: Photo[];
}
- ManyToMany()
双方都必须使用,而且必须有一方使用@JoinTable()
@Entity()
export class Post {@ManyToOne(type => Category)@JoinColumn({name: "cat_id",// 指定列名referencedColumnName: "name" // 引用的Category的列名})category: Category;
}
- JoinColumn()
指定关系列字段,用于一对一,多对一和多对多,可以设置 cascade,createForeignKeyConstraints,以及另一面的关系属性。 - JoinTable()
用于多对多添加中间表,并指定拥有关系的列,只需要一方添加即可。一般要配合@ManyToMany()使用,还可以配置关联表名称和指定关联的列名和关联表的列名 - RelationId()
可以获取关联的实体的id,包括多对一和多对多,此 id 仅用于展示,对其修改并不会增删改关系
@Entity()
export class Post {@ManyToOne(type => Category)category: Category;@RelationId((post: Post) => post.category) // 需要指定目标关系categoryId: number;
}@Entity()
export class Post {@ManyToMany(type => Category)categories: Category[];@RelationId((post: Post) => post.categories)categoryIds: number[];
}