typeorm连表查没有关联关系的实体

简介: typeorm连表查没有关联关系的实体

深入探究 TypeORM:前端开发者的后端数据操作利器

在现代的软件开发中,前后端分离已经成为了一种趋势。作为前端开发者,我们有时也需要涉足后端领域,特别是在处理数据持久化时。当我们谈论数据持久化,数据库无疑是其中的核心组件。但对于前端开发者来说,直接操作数据库可能会显得有些陌生和复杂。这时,ORM(对象关系映射)工具就派上了用场。在Node.js生态系统中,TypeORM是一个非常受欢迎的ORM选择。

什么是 TypeORM?

TypeORM 是一个在 Node.js、Browser、Cordova、PhoneGap、Ionic、React Native、NativeScript、Expo 和 Electron 平台上支持 TypeScript 和 JavaScript(ES5, ES6, ES7, ES8)的 ORM。它可以在 NodeJS、浏览器、Cordova、PhoneGap 和 Ionic 中运行,支持 MySQL / MariaDB / Postgres / SQLite / Microsoft SQL Server / Oracle / sql.js 等多种数据库,并提供了强大的模型定义、数据操作等功能。

为何选择 TypeORM?

  1. 类型安全:由于 TypeORM 支持 TypeScript,因此它提供了类型安全的数据操作。这意味着在编译时就能捕获许多常见的错误。
  2. 易于上手:对于前端开发者来说,TypeORM 的 API 设计直观且友好,很多概念与前端框架中的模式相似。
  3. 活跃的社区:TypeORM 有一个庞大的用户基础和活跃的社区,这意味着遇到问题时可以迅速找到帮助。
  1. 支持多种数据库:无论是关系型数据库还是非关系型数据库,TypeORM 都提供了良好的支持。

开始使用 TypeORM

在使用 TypeORM 之前,需要先安装相应的依赖:

npm install typeorm

连接数据库

首先,需要创建一个数据库连接。这通常在一个名为 app.tsindex.ts 的文件中完成:

import { createConnection } from 'typeorm';

createConnection({
  type: 'mysql',
  host: 'localhost',
  port: 3306,
  username: 'test',
  password: 'test',
  database: 'test',
  entities: [__dirname + '/entity/*.js'],
  synchronize: true,
}).then(connection => {
  console.log('Connected to the database');
}).catch(error => {
  console.log('Error connecting to the database:', error);
});

在上面的代码中,createConnection 方法接受一个包含数据库连接信息的对象。entities 属性指定了实体类的位置,这些实体类将映射到数据库中的表。synchronize 属性设置为 true 时,TypeORM 将自动同步实体类和数据库表的结构。

定义实体

实体是 TypeORM 中的核心概念,它代表了数据库中的一个表。例如,我们可以定义一个 User 实体:

import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class User {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name: string;

  @Column()
  email: string;
}

在上面的代码中,@Entity 装饰器标记了这个类是一个实体类。@PrimaryGeneratedColumn 装饰器表示 id 属性是主键,并且是自动生成的。@Column 装饰器标记了其他的列。

数据操作

有了实体类之后,就可以进行数据的增删改查了。以下是一些基本的操作示例:

import { getRepository } from 'typeorm';
import { User } from './entity/User';

// 查找用户
const userRepository = getRepository(User);
const user = await userRepository.findOne({ email: 'example@example.com' });

// 创建用户
const newUser = new User();
newUser.name = 'John Doe';
newUser.email = 'john@example.com';
await userRepository.save(newUser);

// 更新用户
user.name = 'Jane Doe';
await userRepository.save(user);

// 删除用户
await userRepository.delete(user.id);

在上面的代码中,getRepository 方法用于获取指定实体的存储库,这个存储库提供了对实体进行增删改查的方法。

进阶使用

当然,让我们更深入地探讨TypeORM的一些进阶功能,这些功能在构建复杂应用程序时特别有用。

关系映射

在关系型数据库中,数据通常分布在多个相关联的表中。TypeORM通过关系映射装饰器(如@OneToOne@OneToMany@ManyToOne@ManyToMany)允许你在实体类之间建立这些关系。这意味着你可以轻松地在TypeORM实体之间创建外键关系,并通过简单的API调用访问相关联的数据。

例如,如果你有一个User实体和一个Profile实体,每个用户都有一个个人资料,你可以这样设置关系:

@Entity()
export class User {
  // ...其他字段

  @OneToOne(type => Profile, profile => profile.user)
  profile: Profile;
}

@Entity()
export class Profile {
  // ...其他字段

  @OneToOne(type => User, user => user.profile)
  user: User;
}

使用关系映射后,你可以通过简单的API调用获取用户的个人资料,或者通过个人资料获取用户信息。

事务管理

事务是一系列必须作为单个工作单元执行的数据库操作。如果事务中的所有操作都成功,则事务被提交,并且更改永久保存在数据库中。如果事务中的任何操作失败,则整个事务都会回滚,数据库恢复到事务开始之前的状态。

TypeORM提供了强大的事务管理功能,允许你在多个操作之间保持数据一致性。你可以使用QueryRunner类或getConnection().transaction()方法来管理事务。

const queryRunner = connection.createQueryRunner();

await queryRunner.connect();
await queryRunner.startTransaction();

try {
  // 执行一些数据库操作
  // ...

  await queryRunner.commitTransaction();
} catch (error) {
  await queryRunner.rollbackTransaction();
} finally {
  await queryRunner.release();
}

或者使用更简洁的transaction方法:

await connection.transaction(async manager => {
  // 执行一些数据库操作,使用manager代替常规repository
  // ...
});

查询构建器

查询构建器是TypeORM中用于构建和执行复杂数据库查询的强大工具。它提供了链式调用语法,使得构建查询变得简单且直观。你可以使用查询构建器来创建各种类型的查询,包括选择、插入、更新和删除操作。

下面是一个使用查询构建器选择用户的例子:

const users = await connection.getRepository(User).createQueryBuilder("user")
  .where("user.name = :name", { name: "John" })
  .orWhere("user.email = :email", { email: "john@example.com" })
  .getMany();

查询构建器还支持更复杂的查询,如连接多个表、分组、排序以及使用原生SQL片段等。


通过这些进阶功能,TypeORM为开发者提供了一个全面且灵活的解决方案,以应对各种数据持久化挑战。无论是构建简单的CRUD应用还是复杂的业务逻辑,TypeORM都能提供所需的工具和抽象,使数据库操作变得更加容易和可维护。

注意:orm框架中,尽量不要加外键关联

弱弱的问一下

你们觉得typeorm好用嘛?为啥我觉得挺麻烦的啊?联查必须要给定一个关系,也就是说必须有外键,而且设置起来必须有manytoone和onetomany,而且储存的时候也必须按照他的一套来,而且manytoone的关联表竟然不返回主表的id,还要自己再指定一个比如说user_id的字段自己保存了,才能返回,他自己生成的userId并不返回。而且他的tree实体,看起来挺好的,但是用起来,真是难用,因为没法指定where条件啊。还是我不会用啊?就问问大家所有的orm框架都这么难搞嘛?我已经没写过sql很多年了。就拿一个查tree模型部门结构来说,我是自己写的先查根,再遍历根查孩子,这样子递归,可是这样子就有点拉跨,多查了很多次数据库,这样算法复杂度一下子上去了,部门少还没事。我就很郁闷,想知道大家都是怎么用orm框架的啊

连表查没有关联关系的实体

Dictionary_type实体

//定义Dictionary_type实体,字典类型
@EntityModel()
export class Dictionary_type {

  @PrimaryGeneratedColumn("uuid")
  id: string;

  @Column({comment: "编码",nullable: true,})
  code: string;

  @Column({comment: "状态", nullable: true,default:1})
  state: number;

  @Column({comment: "字典类型名称", nullable: true})
  text: string;
  

  @CreateDateColumn()
  creatDate: string;

  @UpdateDateColumn()
  updateDate: string;

}

Dictionary_item 实体

在实体中设置type_id存放Dictionary_type主键id

@EntityModel()
export class Dictionary_item {

  @PrimaryGeneratedColumn("uuid")
  id: string;

  @Column({comment: "序号",nullable: true,})
  sort: number;

  @Column({comment: "字典类型", nullable: true,})
  type_id: string;

  @Column({comment: "字典类型值", nullable: true})
  value: number;

  @Column({comment: "字典类型内容", nullable: true})
  text: string;


  @CreateDateColumn()
  creatDate: string;

  @UpdateDateColumn()
  updateDate: string;

}

Post和PostExtend中没有设置关联关系,所以我们并不能在find option中关联两个实体进行连表查询。

但是可以用queryBuilder

 const posts = await getConnection()
          .createQueryBuilder(Post, 'post')
          .leftJoinAndSelect(PostExtend, 'postExtend', 'post.id=postExtend.postId')
         .getManyAndCount()
return posts;

查询结果:

[
    [
        {
            "id": 1,
            "title": "北京申奥成功",
            "content": "2003年奥林匹克运动会将在北京举行,北京欢迎你!"
        }
    ],
    1
]

上面的查询结果中并没有PostExtend的数据,这是因为不能确定两个实体之间的关联关系,所以无法确定查询结果的显示形式。

当然,也可以通过 getRawMany() 方法获取原生字段来获取PostExtend的信息,但是这样的查询结果显示并不友好。

1 const posts = await getConnection()
2             .createQueryBuilder(Post, 'post')
3             .leftJoinAndSelect(PostExtend, 'postExtend', 'post.id=postExtend.postId')
4             .getRawMany()
5         return posts;

结果:


 1 [
 2     {
 3         "post_id": 1,
 4         "post_title": "北京申奥成功",
 5         "post_content": "2003年奥林匹克运动会将在北京举行,北京欢迎你!",
 6         "postExtend_id": 1,
 7         "postExtend_postId": 1,
 8         "postExtend_likeCount": 999,
 9         "postExtend_readCount": 10000,
10         "postExtend_forwardCount": 666
11     }
12 ]

如果想要将原生字段映射到属性,可以使用 leftJoinAndMapOne() ,如果时一对多还可以使用 leftJoinAndMapMany()

 const posts = await getConnection()
             .createQueryBuilder(Post, 'post')
             .leftJoinAndMapOne('post.postExtend',PostExtend, 'postExtend', 'post.id=postExtend.postId')
             .getManyAndCount()
         return posts;

结果:

[
 2     [
 3         {
 4             "id": 1,
 5             "title": "北京申奥成功",
 6             "content": "2003年奥林匹克运动会将在北京举行,北京欢迎你!",
 7             "postExtend": {
 8                 "id": 1,
 9                 "postId": 1,
10                 "likeCount": 999,
11                 "readCount": 10000,
12                 "forwardCount": 666
13             }
14         }
15     ],
16     1
17 ]

postExtend的数据被映射到post.postExtend,这样的结果清晰明了。

相关文章
|
小程序 数据安全/隐私保护 Android开发
八米云-N1盒子、机顶盒等设备-小白保姆式超详细刷机教程
这里以魔百盒CM211-1为例,本次刷机用到的零碎工具比较多,不过都是常见刚需设备,大家可以按照清单核对一下。 目前只支持S905 L3、L3a、L2 系列的各种盒子
2441 1
八米云-N1盒子、机顶盒等设备-小白保姆式超详细刷机教程
|
19天前
|
Ubuntu 应用服务中间件 Linux
使用阿里云服务器部署网站,保姆级教程(nginx部署及宝塔部署)
本文详解如何在阿里云轻量服务器上部署网站,涵盖两种主流方案:一是手动配置Nginx(含安装、启停、修改配置及静态文件部署);二是使用图形化宝塔面板(一键安装、建站、上传文件与路径配置)。配套Xshell远程连接和Xftp文件管理,适合新手与进阶用户。
|
SQL 运维 监控
Nest.js 实战 (十):使用 winston 打印和收集日志记录
这篇文章介绍了在Nest服务中如何使用Winston记录日志。文章首先强调了日志记录在后台服务中的重要性,接着提到Nest默认的内部日志记录器,并指出可以通过@nestjs/common包中的Logger类来全面控制日志系统的行为。文章还提到,为了在生产环境中实现更高级的日志功能,可以使用如Winston之类的Node.js日志包。接下来,文章介绍了如何在Nest服务中使用Winston记录日志,包括安装相关依赖、创建winston配置文件以及实现简单的日志记录示例。最后,文章指出更高级的自定义日志功能需要读者自己去探索。
905 0
Nest.js 实战 (十):使用 winston 打印和收集日志记录
|
Web App开发 移动开发 编解码
浏览器播放RTSP视频流几种解决方案
Streamedian 提供了一种“html5_rtsp_player + websock_rtsp_proxy”的技术方案,可以通过html5的video标签直接播放RTSP的视频流。
2867 0
|
存储 程序员 C++
内存管理概念 (二)
内存管理概念 (二)
|
JavaScript Java 测试技术
基于SpringBoot+Vue的旅游管理系统的设计与实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue的旅游管理系统的设计与实现(源码+lw+部署文档+讲解等)
382 1
|
存储 关系型数据库 数据库连接
[Nestjs] 使用Typeorm配置数据库配置时区的方法
如果在使用 TypeORM 和 NestJS 进行数据库操作时,遇到数据库时间不准确的问题,可以考虑以下几个解决办法: 1. 使用数据库服务器的时间:确保数据库服务器的时间是准确的,并且与应用程序运行的服务器时间同步。这样可以避免由于时间差异导致的数据不准确问题。 2. 设置数据库连接的时区:通过在 TypeORM 配置中设置 timezone 属性,将数据库连接的时区设置为与应用程序所在地区相匹配。例如,对于 PostgreSQL 数据库:
1416 0