返回介绍

typeorm 增删改查操作

发布于 2024-01-18 22:07:39 字数 14088 浏览 0 评论 0 收藏 0

访问数据库的方式有哪些? typeorm 增删改查操作的方式有哪些?

多种访问数据库的方式

第一种: Connection

import { Injectable } from '@nestjs/common';
import { Connection } from 'typeorm';
import { UsersEntity } from './entities/user.entity';

@Injectable()
export class UserService {
  constructor(
    private readonly connection: Connection,
  ) { }

  async test() {
    // 使用封装好方法:
    return await this.connection
      .getRepository(UsersEntity)
      .findOne({ where: { id: 1 } });

// 使用 createQueryBuilder:
    return await this.connection
      .createQueryBuilder()
      .select('user')
      .from(UsersEntity, 'user')
      .where('user.id = :id', { id: 1 })
      .getOne();
  }
}

第二种: Repository ,需要 @nestjs/typeormInjectRepository 来注入实体

import { Injectable } from '@nestjs/common';
import { Repository } from 'typeorm';
import { UsersEntity } from './entities/user.entity';
import { InjectRepository } from '@nestjs/typeorm';

@Injectable()
export class UserService {
  constructor(
  @InjectRepository(UsersEntity)  注入实体
private readonly usersRepository: Repository<UsersEntity>,
  ) { }

  async test() {
  // 使用封装好方法:
    return await this.usersRepository.find({ where: { id: 1 } });

// 使用 createQueryBuilder:
    return await this.usersRepository
      .createQueryBuilder('user')
      .where('id = :id', { id: 1 })
      .getOne();
  }
}

第三种: getConnection() :语法糖,是 Connection 类型

import { Injectable } from '@nestjs/common';
import { getConnection } from 'typeorm';
import { UsersEntity } from './entities/user.entity';

@Injectable()
export class UserService {
  async test() {
  // 使用封装好方法:
    return await getConnection()
      .getRepository(UsersEntity)
      .find({ where: { id: 1 } });

// 使用 createQueryBuilder:
    return await getConnection()
      .createQueryBuilder()
      .select('user')
      .from(UsersEntity, 'user')
      .where('user.id = :id', { id: 1 })
      .getOne();
  }
}

第四种: getRepository :语法糖

import { Injectable } from '@nestjs/common';
import { getRepository } from 'typeorm';
import { UsersEntity } from './entities/user.entity';

@Injectable()
export class UserService {
  async test() {
  // 使用封装好方法:
    return await getRepository(UsersEntity).find({ where: { id: 1 } });

// 使用 createQueryBuilder:
    return await getRepository(UsersEntity)
      .createQueryBuilder('user')
      .where('user.id = :id', { id: 1 })
      .getOne();
  }
}

第五种: getManager

import { Injectable } from '@nestjs/common';
import { getManager } from 'typeorm';
import { UsersEntity } from './entities/user.entity';

@Injectable()
export class UserService {
  async test() {
  // 使用封装好方法:
    return await getManager().find(UsersEntity, { where: { id: 1 } });

// 使用 createQueryBuilder:
return await getManager()
      .createQueryBuilder(UsersEntity, 'user')
      .where('user.id = :id', { id: 1 })
      .getOne();
  }
}

简单总结

使用的方式太多,建议使用: 2,4 ,比较方便

Connection 核心类:

  • connection 等于 getConnection
  • connection.manager 等于 getManager , 等于 getConnection.manager
  • connection.getRepository 等于 getRepository , 等于 getManager.getRepository
  • connection.createQueryBuilder 使用 QueryBuilder
  • connection.createQueryRunner 开启事务
  1. EntityManagerRepository 都封装了操作数据的方法,注意:两者的使用方式是不一样的,(实在不明白搞这么多方法做什么,学得头大) getManagerEntityManager 的类型, getRepositoryRepository 的类型
  2. 都可以使用 createQueryBuilder ,但使用的方式略有不同

增删改查的三种方式

  • 第一种:使用 sql 语句,适用于 sql 语句熟练的同学
  • 第二种: typeorm 封装好的方法,增删改 + 简单查询
  • 第三种: QueryBuilder 查询生成器,适用于关系查询,多表查询,复杂查询
  • 其实底层最终都会生成 sql 语句,只是封装了几种方式而已,方便人们使用。

第一种:sql 语句

export class UserService {
  constructor(
    @InjectRepository(UsersEntity)
    private readonly usersRepository: Repository<UsersEntity>,
  ) { }

  async findAll() {
    return await this.usersRepository.query('select * from users');  // 在 query 中填写 sql 语句
  }
}

第二种:typeorm 封装好的 api 方法

这里使用第二种访问数据库的方式

export class UserService {
  constructor(
    @InjectRepository(UsersEntity)
    private readonly usersRepository: Repository<UsersEntity>,
  ) { }

  async findAll() {
    return await this.usersRepository.findAndCount();  // 封装好的方法
  }
}

api 方法

增
save(user)            创建:返回该数据的所有字段
insert(user)          快速插入一条数据,插入成功:返回插入实体,与 save 方法不同的是,它不执行级联、关系和其他操作。
删
remove(user)          删除:返回该数据的可见字段
softRemove(user);     拉黑:返回该数据的可见字段,该删除实体必须拥有 @DeleteDateColumn() 字段,被拉黑的用户还存在数据库中,但无法被 find 查找到,会在 @DeleteDateColumn() 字段中添加删除时间,可使用 recover 恢复
改
update(id, user)      更新:返回更新实体,不是该数据的字段
恢复
recover({ id })       恢复:返回 id,将被 softRemove 删除(拉黑)的用户恢复,恢复成功后可以被 find 查找到


查找全部
find()
find({id:9})                   条件查找,写法一,找不到返回空对象
find({where:{id:10}})          条件查找,写法二,找不到返回空对象
findAndCount()                 返回数据和总的条数

查找一个
findOne(id);                       根据 ID 查找,找不到返回 undefined
findOne({ where: { username } });  条件查找,找不到返回 undefined

根据 ID 查找一个或多个
findByIds([1,2,3]);            查找 n 个,全部查找不到返回空数组,找到就返回找到的

其他
hasId(new UsersEntity())       检测实体是否有合成 ID,返回布尔值
getId(new UsersEntity())       获取实体的合成 ID,获取不到返回 undefined
create({username: 'admin12345', password: '123456',})  创建一个实体,需要调用 save 保存
count({ status: 1 })           计数,返回数量,无返回 0
increment({ id }, 'age', 2);   增加,给条件为 id 的数据的 age 字段增加 2,成功返回改变实体
decrement({ id }, 'age', 2)    减少,给条件为 id 的数据的 age 字段增加 2,成功返回改变实体

谨用
findOneOrFail(id)              找不到直接报 500 错误,无法使用过滤器拦截错误,不要使用
clear()                        清空该数据表,谨用!!!

find 更多参数

this.userRepository.find({
    select: ["firstName", "lastName"],             要的字段
    relations: ["photos", "videos"],               关系查询
    where: {                                       条件查询
        firstName: "Timber",
        lastName: "Saw"
    },
    where: [{ username: "li" }, { username: "joy" }],   多个条件 or, 等于:where username = 'li' or username = 'joy'
    order: {                                       排序
        name: "ASC",
        id: "DESC"
    },
    skip: 5,                                       偏移量
    take: 10,                                      每页条数
    cache: 60000                                   启用缓存:1 分钟
});

find 进阶选项

TypeORM 提供了许多内置运算符,可用于创建更复杂的查询

import { Not, Between, In } from "typeorm";
return await this.usersRepository.find({
    username: Not('admin'),
});
将执行以下查询:
SELECT * FROM "users" WHERE "username" != 'admin'


return await this.usersRepository.find({
    likes: Between(1, 10)
});
SELECT * FROM "users" WHERE "likes" BETWEEN 1 AND 10


return await this.usersRepository.find({
    username: In(['admin', 'admin2']),
});
SELECT * FROM "users" WHERE "title" IN ('admin', 'admin2')

更多查看官网

第三种QueryBuilder 查询生成器

使用链式操作

QueryBuilder 增,删,改

// 增加
return await this.usersRepository
  .createQueryBuilder()
  .insert()                       声明插入操作
  .into(UsersEntity)              插入的实体
  .values([                       插入的值,可插入多个
    { username: 'Timber', password: '123456' },
    { username: 'Timber2', password: '123456' },
  ])
  .execute();                     执行


// 修改
return this.usersRepository
  .createQueryBuilder()
  .update(UsersEntity)
  .set({ username: 'admin22' })
  .where('id = :id', { id: 2 })
  .execute();


// 删除
return this.usersRepository
  .createQueryBuilder()
  .delete()
  .from(UsersEntity)
  .where('id = :id', { id: 8 })
  .execute();


// 处理异常:请求成功会返回一个对象, 如果 raw.affectedRows != 0 就是成功
"raw": {
      "fieldCount": 0,
      "affectedRows": 2,
      "insertId": 13,
      "serverStatus": 2,
      "warningCount": 0,
      "message": "&Records: 2  Duplicates: 0  Warnings: 0",
      "protocol41": true,
      "changedRows": 0
}

查询

简单例子

export class UserService {
  constructor(
    @InjectRepository(UsersEntity)
    private readonly usersRepository: Repository<UsersEntity>,
  ) { }

  async findAll() {
    return await this.usersRepository
    .createQueryBuilder('user')                      创建生成器,参数:别名
    .where('user.id = :id', { id: id })              条件
    .innerJoinAndSelect('user.avatar', 'avatar')     关系查询
    .addSelect('user.password')                      添加显示字段
    .getOne();                                       获取一条数据
  }
}

QueryBuilder 查询生成器说明

查询单表

访问数据库的方式不同:

方式一:没有指定实体,需要使用 from 指定实体
return await getConnection()
      .createQueryBuilder()
      .select('user.username')             ‘user’:全部字段,‘user.username’:只获取 username
      .from(UsersEntity, 'user')           参 1:连接的实体, 参 2:别名
      .where('user.id = :id', { id: 1 })
      .getOne();

方式二:指定实体:默认获取全部字段
return await getConnection()
      .createQueryBuilder(UsersEntity, 'user')   指定实体
      .where('user.id = :id', { id: 1 })
      .getOne();

方式三: 已经在访问时指定了实体:默认获取全部字段
return await this.usersRepository
      .createQueryBuilder('user')          别名
      .where('user.id = :id', { id: 1 })
      .getOne();

获取结果

.getSql();          获取实际执行的 sql 语句,用于开发时检查问题
.getOne();          获取一条数据(经过 typeorm 的字段处理)
.getMany();         获取多条数据
.getRawOne();       获取一条原数据(没有经过 typeorm 的字段处理)
.getRawMany();      获取多条原数据
.stream();          返回流数据

如:经过 typeorm 的字段处理,获取到的就是实体设计时的字段
{
    "status": 200,
    "message": "请求成功",
    "data": {
        "id": 1,
        "username": "admin",
        "gender": "male",
        "age": 18,
        "status": 1,
        "createdAt": "2021-04-26T09:58:54.469Z",
        "updatedAt": "2021-04-28T14:47:36.000Z",
        "deletedAt": null
    }
}

如:没有经过 typeorm 的字段处理,将数据库的字段原生不动的显示出来
{
    "status": 200,
    "message": "请求成功",
    "data": {
        "user_id": 1,
        "user_username": "admin",
        "user_gender": "male",
        "user_age": 18,
        "user_status": 1,
        "user_created_at": "2021-04-26T09:58:54.469Z",
        "user_updated_at": "2021-04-28T14:47:36.000Z",
        "user_deleted_at": null
    }
}

查询部分字段

.select(["user.id", "user.name"])
实际执行的 sql 语句:SELECT user.id, user.name FROM users user;

添加隐藏字段:实体中设置 select 为 false 时,是不显示字段,使用 addSelect 会将字段显示出来
.addSelect('user.password')

where 条件

.where("user.name = :name", { name: "joy" })
等于
.where("user.name = :name")
.setParameter("name", "Timber")
实际执行的 sql 语句:SELECT * FROM users user WHERE user.name = 'joy'

多个条件
.where("user.firstName = :firstName", { firstName: "Timber" })
.andWhere("user.lastName = :lastName", { lastName: "Saw" });
实际执行的 sql 语句:SELECT * FROM users user WHERE user.firstName = 'Timber' AND user.lastName = 'Saw'

in
.where("user.name IN (:...names)", { names: [ "Timber", "Cristal", "Lina" ] })
实际执行的 sql 语句:SELECT * FROM users user WHERE user.name IN ('Timber', 'Cristal', 'Lina')

or
.where("user.firstName = :firstName", { firstName: "Timber" })
.orWhere("user.lastName = :lastName", { lastName: "Saw" });
实际执行的 sql 语句:SELECT * FROM users user WHERE user.firstName = 'Timber' OR user.lastName = 'Saw'

子句
const posts = await connection
  .getRepository(Post)
  .createQueryBuilder("post")
  .where(qb => {
    const subQuery = qb
      .subQuery()
      .select("user.name")
      .from(User, "user")
      .where("user.registered = :registered")
      .getQuery();
    return "post.title IN " + subQuery;
  })
  .setParameter("registered", true)
  .getMany();
实际执行的 sql 语句:select * from post where post.title in (select name from user where registered = true)

having 筛选

.having("user.firstName = :firstName", { firstName: "Timber" })
.andHaving("user.lastName = :lastName", { lastName: "Saw" });
实际执行的 sql 语句:SELECT ... FROM users user HAVING user.firstName = 'Timber' AND user.lastName = 'Saw'

orderBy 排序

.orderBy("user.name", "DESC")
.addOrderBy("user.id", "asc");
等于
.orderBy({
  "user.name": "ASC",
  "user.id": "DESC"
});

实际执行的 sql 语句:SELECT * FROM users user order by user.name asc, user.id desc;

group 分组

.groupBy("user.name")
.addGroupBy("user.id");

关系查询(多表)

1 参:你要加载的关系,2 参:可选,你为此表分配的别名,3 参:可选,查询条件

左关联查询
.leftJoinAndSelect("user.profile", "profile")     

右关联查询
.rightJoinAndSelect("user.profile", "profile")    

内联查询
.innerJoinAndSelect("user.photos", "photo", "photo.isRemoved = :isRemoved", { isRemoved: false })         


例子:
const result = await this.usersRepository
.createQueryBuilder('user')
    .leftJoinAndSelect("user.photos", "photo")
    .where("user.name = :name", { name: "joy" })
  .andWhere("photo.isRemoved = :isRemoved", { isRemoved: false })
  .getOne();

实际执行的 sql 语句:
SELECT user.*, photo.* 
FROM users user
LEFT JOIN photos photo ON photo.user = user.id
WHERE user.name = 'joy' AND photo.isRemoved = FALSE;


const result = await this.usersRepository
.innerJoinAndSelect("user.photos", "photo", "photo.isRemoved = :isRemoved", { isRemoved: false })
    .where("user.name = :name", { name: "Timber" })
    .getOne();

实际执行的 sql 语句:
SELECT user.*, photo.* FROM users user
INNER JOIN photos photo ON photo.user = user.id AND photo.isRemoved = FALSE
WHERE user.name = 'Timber';


多个关联
const result = await this.usersRepository
  .createQueryBuilder("user")
  .leftJoinAndSelect("user.profile", "profile")
  .leftJoinAndSelect("user.photos", "photo")
  .leftJoinAndSelect("user.videos", "video")
  .getOne();

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文