第四章 初级CUD 关系
- 会用
getRepository拿到实体的仓库 - 掌握写操作:
save/insert/update/upsert的区别 - 掌握读操作:
find/findBy/findOne/findOneBy/findOneOrFail/count/countBy/exists/existsBy - 掌握删操作:
remove/delete/clear,并预告softDelete - 避开"找不到返回 null"和"save 返回值不完整"两个高频坑
核心改变
Repository 就是表格的管家:每注册一个实体,TypeORM 就给你配一个专属管家,增删改查都通过它:
ts
const userRepo = ds.getRepository(User);管家只管这一张表。想操作另一张表,再拿另一个管家:
ds.getRepository(Product)。
写操作
save 插入/更新 二合一
- 插入
ts
import { AppDataSource } from "./data-source";
import { User } from "./entities/User";
AppDataSource.initialize()
.then(async () => {
const user = new User();
user.firstName = "JSOPY";
user.lastName = "Saw";
user.age = 25;
await AppDataSource.manager.save(user);
console.log("Saved a new user with id: " + user.id);
})
.catch((error) => console.log(error));- 更新
ts
import { AppDataSource } from "./data-source";
import { User } from "./entities/User";
AppDataSource.initialize()
.then(async () => {
await AppDataSource.manager.save(User, { id: 2, age: 35 });
console.log("修改成功 " + 2);
})
.catch((error) => console.log(error));⚠️ 实测注意:save({ id: 1, age: 19 }) 部分更新时,数据库里其他字段不会被清空(不会写成 NULL),但返回值只包含你传入的字段(如 { id: 1, age: 19 }),不是数据库完整行。需要完整实体就再查一次。
insert: 插入
ts
import { AppDataSource } from "./data-source";
import { User } from "./entities/User";
AppDataSource.initialize()
.then(async () => {
const user = new User();
user.firstName = "new_5";
user.lastName = "new_last_5";
user.age = 57;
const user2 = new User();
user2.firstName = "new_6";
user2.lastName = "new_last_6";
user2.age = 7;
const users = [user, user2];
const result = await AppDataSource.manager.insert(User, users);
console.log("插入成功 " + JSON.stringify(result));
if (result.raw.affectedRows > 0) {
console.log("插入成功");
}
})
.catch((error) => console.log(error));update: 更新
ts
import { AppDataSource } from "./data-source";
import { User } from "./entities/User";
AppDataSource.initialize()
.then(async () => {
const result = await AppDataSource.manager.update(
User,
{ id: 3 },
{ age: 65 },
);
console.log("修改成功 " + JSON.stringify(result));
if (result.affected > 0) {
console.log("修改成功");
}
})
.catch((error) => console.log(error));save vs insert vs update 对比
| 名称 | save | insert | update |
|---|---|---|---|
| 语义 | 有主键更新/无则插入 | 只插入,撞主键报错 | 只更新 |
| 返回值 | (传入字段合并出的)实体 | InsertResult(identifiers 等) | UpdateResult(affected) |
| 批量效率 | 多条语句 | 一条批量 SQL | 一条 SQL |
| 是否触发实体钩子 | 是(详见监听器官章节) | 否 | 否 |
| 是否先查数据库 | 带主键时会先查 | 否 | 否 |
删操作
| 方法 | 说明 |
|---|---|
remove(entity) | 先查出实体再删;返回被删实体(其 id 已被置为 undefined);触发实体钩子 |
delete(criteria) | 直接发 DELETE SQL,不查实体;criteria 可以是 id、id 数组或 where 对象 |
softDelete(criteria) | 软删除:只填删除标记列,不真删(需要 @DeleteDateColumn,详见第 16 章) |
clear() | TRUNCATE 清空整表,自增计数重置为 1,不可恢复 |
- remove
ts
import { AppDataSource } from "./data-source";
import { User } from "./entities/User";
AppDataSource.initialize()
.then(async () => {
const entity = await AppDataSource.manager.findOneBy(User, {
firstName: "new_6",
});
await AppDataSource.manager.remove(entity!); // 先查再删
})
.catch((error) => console.log(error));- delete
ts
import { AppDataSource } from "./data-source";
import { User } from "./entities/User";
AppDataSource.initialize()
.then(async () => {
const result = await AppDataSource.manager.delete(User, { id: 7 });
console.log("删除成功 " + JSON.stringify(result));
if (result.raw.affectedRows > 0) {
console.log("删除成功");
}
})
.catch((error) => console.log(error));- clear
ts
import { AppDataSource } from "./data-source";
import { User } from "./entities/User";
AppDataSource.initialize()
.then(async () => {
await AppDataSource.manager.clear(User);
})
.catch((error) => console.log(error));