ORM 是 Object-Relational Mapping 的缩写,即对象关系映射。 也就是说把关系型数据库的表映射成面向对象的 class,表的字段映射成对象的属性映射,表与表的关联映射成属性的关联。
初始化 TypeORM 项目
kotlin
npx typeorm@latest init --name typeorm-all-feature --database mysql
连接配置
javascript
// src/data-source.ts
import "reflect-metadata"
import {DataSource} from "typeorm"
import {User} from "./entity/User"
export const AppDataSource = new DataSource({
type: "mysql", // 数据库类型,postgres/mysql/mariadb/sqlite/oracle/mssql/cockroachdb
host: "localhost", // 数据库主机
port: 3306, // 数据库端口
username: "root", // 数据库用户名
password: "admin", // 数据库密码
database: "hello-mysql", // 数据库名称
synchronize: true, // 是否自动同步数据库表结构
logging: true, // 是否打印 typeorm 生成的 sql 语句
entities: [User], // 指定有哪些数据库的表对应的实体(Entity);也可以通过这种方式指定: ['./**/entity*.ts']
migrations: [], // 迁移文件
subscribers: [], // Entity 声明周期的订阅者,比如 insert/update/remove 前后,可以加入一些逻辑
poolSize: 10, // 数据库连接池中连接的最大连接数
connectorPackage: "mysql2", // 指定用的数据库连接器包
extra: { // 额外发送给连接器包的参数
authPlugins: 'sha256_password'
}
})
安装 mysql2
css
npm install --save mysql2
实体
实体(Entity)是数据库中的表,实体类是 TypeScript 中的类,实体类与数据库表结构一一对应。
less
import {Entity, PrimaryGeneratedColumn, Column} from "typeorm"
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number
@Column()
firstName: string
@Column()
lastName: string
@Column()
age: number
}
- 默认映射关系: 主键为 int 类型、自增;string 类型为 varchar(255);number 类型为 int 类型;
- 修改映射类型则通过 type 属性指定,type 为数据库中对应的类型
less
// src/entity/Sanshi.ts
import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"
@Entity({
name: 'san_shi' // 指定表名,默认表名是类名
})
export class Sanshi {
// @PrimaryGeneratedColumn() // 默认 int 类型,自增
@PrimaryGeneratedColumn({
comment: '这是 id' // 添加注释
})
id: number
// @Column() // 默认 varchar(255)
@Column({
name: 'key',
type: 'text', // 指定字段类型,默认 varchar(255)
comment: '这是 key'
})
key: string
@Column({
unique: true, // 添加唯一索引
nullable: false, // 允许为 null
length: 10, // 指定字段长度
type: 'varchar',
default: 'label'
})
label: string
// @Column() // 默认 int 类型
@Column({
type: 'double', // 指定字段类型,默认 int
})
value: number
}
同步修改到数据库
arduino
npm run start
新增
javascript
// src/index.ts
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
const user = new User()
// user.id = 1 // 不指定 id 是新增,指定则是修改
user.firstName = "San"
user.lastName = "Shi"
user.age = 18
await AppDataSource.manager.save(user)
}).catch(error => console.log(error))
批量新增
csharp
// 批量插入
const personArr = [
{ firstName: "San1", lastName: "Shi1", age: 18},
{ firstName: "San2", lastName: "Shi2", age: 18},
{ firstName: "San3", lastName: "Shi3", age: 18},
]
await AppDataSource.manager.save(Person, personArr)
编辑
javascript
// src/index.ts
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
const user = new User()
user.id = 1 // 不指定 id 是新增,指定则是修改
user.firstName = "San"
user.lastName = "Shi"
user.age = 18
await AppDataSource.manager.save(user)
console.log("Saved a new user with id: " + user.id)
}).catch(error => console.log(error))
批量修改
yaml
// 批量修改
const personArr = [
{ id: 1, firstName: "San1", lastName: "Shi1", age: 17},
{ id: 2, firstName: "San2", lastName: "Shi2", age: 18},
{ id: 4, firstName: "San0", lastName: "Shi0", age: 19},
]
await AppDataSource.manager.save(Person, personArr)
EntityManager 还有 update 和 insert 方法,分别是修改和插入,但是它们不会先 select 一次,而 save 方法会先查询一次数据库来确定是插入还是修改。
删除和批量删除
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
// 删除
await AppDataSource.manager.delete(User, 1)
// 批量删除
await AppDataSource.manager.delete(User, [2, 3])
}).catch(error => console.log(error))
删除方法 delete 和 remove 的区别
delete 和 remove 的区别是,delete 直接传 id、而 remove 则是传入 entity 对象。
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
// 通过 remove 删除
const rUser = new User();
rUser.id = 4;
await AppDataSource.manager.remove(User, rUser);
}).catch(error => console.log(error))
查询
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
// 查询
const users = await AppDataSource.manager.find(User);
console.log('查询结果: ', users);
}).catch(error => console.log(error))
条件查询
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
// 条件查询
const users2 = await AppDataSource.manager.findBy(User, {
firstName: 'San'
});
console.log('条件查询结果: ', users2);
}).catch(error => console.log(error))
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
AppDataSource.initialize().then(async () => {
/**
* 条件查询2:
* In: 批量查询
*/
const users3 = await AppDataSource.manager.find(User, {
select: {
firstName: true,
age: true
},
where: {
id: In([12, 13, 9]) // 批量查询,id 为 12、13、9 的数据
},
order: {
age: 'ASC'
}
})
console.log('条件查询结果2: ', users3);
}).catch(error => console.log(error))
查询并统计
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
// 查询并统计有多少条记录
const count = await AppDataSource.manager.findAndCount(User)
console.log('查询并统计有多少条记录: ', count);
}).catch(error => console.log(error))
查询并按条件统计
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
// 查询并按条件统计
const count2 = await AppDataSource.manager.findAndCountBy(User, {
firstName: 'San'
})
console.log('查询并按条件统计: ', count2);
}).catch(error => console.log(error))
查询单条
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
AppDataSource.initialize().then(async () => {
// 查询单条
const user2 = await AppDataSource.manager.findOne(User, {
select: {
firstName: true,
age: true
},
where: {
id: 13
},
order: {
age: 'ASC'
}
});
console.log('单条查询结果: ', user2);
}).catch(error => console.log(error))
查询单条并按条件查询
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
AppDataSource.initialize().then(async () => {
// 查询单条并按条件查询
const user3 = await AppDataSource.manager.findOneBy(User, {
age: 18
})
console.log('单条并按条件查询结果: ', user3);
}).catch(error => console.log(error))
查询单条,查不到时返回异常信息
使用 findOneOrFail 和 findOneByOrFail 在查询不到时会抛出一个 EntityNotFoundError 的异常
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
AppDataSource.initialize().then(async () => {
// 查询单条,查不到时返回异常信息
const user4 = await AppDataSource.manager.findOneOrFail(User, {
where: {
id: 9999
}
})
console.log('单条,查不到时返回异常信息(findOneOrFail): ', user4);
const user5 = await AppDataSource.manager.findOneByOrFail(User, {
id: 9999
})
console.log('查询单条,查不到时返回异常信息(findOneByOrFail): ', user5);
}).catch(error => console.log(error))
使用 query 执行 SQL
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
AppDataSource.initialize().then(async () => {
// 使用 query 执行 SQL
const user6 = await AppDataSource.manager.query('SELECT * FROM user WHERE id = 16')
console.log('使用 query 执行 SQL: ', user6);
}).catch(error => console.log(error))
使用 queryBuilder
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
AppDataSource.initialize().then(async () => {
// 使用 queryBuilder
const queryBuilder = await AppDataSource.manager.createQueryBuilder()
const user7 = await queryBuilder.select('user')
.from(User, 'user')
.where('user.id = :id', { id: 17 })
.getOne()
console.log('使用 queryBuilder 查询结果: ', user7);
}).catch(error => console.log(error))
开启事务
用 transaction 方法包裹即可。
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
AppDataSource.initialize().then(async () => {
// 开启事务
await AppDataSource.manager.transaction(async entityManager => {
const user = new User()
user.firstName = "San"
user.lastName = "Shi"
user.age = 18
await entityManager.save(user)
})
}).catch(error => console.log(error))
避免调用每个方法时都传入实体类
可以先调用 getRepository 传入 Entity,拿到专门处理这个 Entity 的增删改查的类,再调用各种方法。
javascript
import {AppDataSource} from "./data-source"
import {User} from "./entity/User"
import {In} from "typeorm";
AppDataSource.initialize().then(async () => {
// 避免调用每个方法时都传入实体类
const userManager = AppDataSource.manager.getRepository(User)
const users4 = await userManager.find({
select: {
firstName: true,
age: true
},
})
console.log('避免调用每个方法时都传入实体类,查询结果: ', users4);
const user4 = await userManager.findOne({
select: {
firstName: true,
age: true
},
where: {
id: 13
},
order: {
age: 'ASC'
}
})
console.log('避免调用每个方法时都传入实体类,单条查询结果: ', user4);
}).catch(error => console.log(error))