Skip to content

第四章 初级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 对比

名称saveinsertupdate
语义有主键更新/无则插入只插入,撞主键报错只更新
返回值(传入字段合并出的)实体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));