TypeScript与TypeORM:类型安全的数据库操作

文章目录

      • 准备工作
        • 安装Node.js
        • 初始化项目
        • 安装依赖
      • 设置数据库连接
      • 创建实体
      • 连接数据库并执行操作
      • 运行应用
      • 关系管理
        • 一对一关系
        • 一对多关系
        • 多对多关系
      • 自定义查询
        • 使用 QueryBuilder
        • 使用原生 SQL 查询
      • 事务处理
      • 迁移管理
        • 创建迁移文件
        • 编写迁移逻辑
        • 应用迁移
      • 性能优化
        • 批量插入
        • 使用缓存

随着前端技术的发展,后端开发也逐渐注重类型安全和开发效率。TypeScript作为一种静态类型语言,可以很好地与JavaScript生态系统集成,而TypeORM则是一个基于TypeScript构建的对象关系映射(ORM)工具,它允许开发者以面向对象的方式操作数据库,同时提供了强大的类型支持。

准备工作

安装Node.js

确保你的机器上已经安装了Node.js,可以通过命令node -v检查版本。

初始化项目

创建一个新的目录作为项目根目录,并在其中初始化一个新的Node.js项目:

mkdir typeorm-tutorial
cd typeorm-tutorial
npm init -y
安装依赖

安装TypeScript、TypeORM以及必要的数据库驱动程序(这里我们以MySQL为例):

npm install typescript typeorm reflect-metadata mysql2
npm install --save-dev @types/node @types/mysql2

接下来,配置TypeScript编译器:

npx tsc --init

编辑tsconfig.json文件,添加以下配置:

{"compilerOptions": {"target": "es6","module": "commonjs","outDir": "./dist","strict": true,"esModuleInterop": true},"include": ["src/**/*"]
}

设置数据库连接

在项目的根目录下创建一个名为.ormconfig.json的文件,用于配置TypeORM连接信息:

{"type": "mysql","host": "localhost","port": 3306,"username": "root","password": "yourpassword","database": "typeorm_tutorial","synchronize": true,"logging": false,"entities": ["src/entities/*.ts"],"migrations": [],"subscribers": [],"cli": {"entitiesDir": "src/entities","migrationsDir": "src/migrations","subscribersDir": "src/subscribers"}
}

创建实体

实体是TypeORM中的核心概念之一,它代表数据库中的表。我们先定义一个简单的用户实体:

src/entities目录下创建User.ts文件:

import { Entity, Column, PrimaryGeneratedColumn } from 'typeorm';@Entity()
export class User {@PrimaryGeneratedColumn()id: number;@Column()name: string;@Column()email: string;@Column({ default: '' })password: string;
}

连接数据库并执行操作

src/index.ts中设置数据库连接,并编写一些基本的CRUD操作:

import { createConnection } from 'typeorm';
import { User } from './entities/User';createConnection().then(async connection => {console.log('Connected to database.');// 创建新用户const user = new User();user.name = 'Alice';user.email = 'alice@example.com';user.password = 'secret';await connection.manager.save(user);// 查询所有用户const users = await connection.manager.find(User);console.log(users);// 更新用户const updatedUser = await connection.manager.findOne(User, user.id);if (updatedUser) {updatedUser.name = 'Alicia';await connection.manager.save(updatedUser);}// 删除用户await connection.manager.remove(updatedUser);await connection.close();
}).catch(error => console.log(error));

运行应用

确保数据库已启动,然后运行:

tsc
node dist/index.js

观察控制台输出,确认数据操作是否成功。

关系管理

在实际应用中,数据通常不是孤立存在的,而是与其他数据之间存在关联。TypeORM 支持多种类型的关系定义,包括一对一(One-to-One)、一对多(One-to-Many)和多对多(Many-to-Many)。

一对一关系

假设我们有两个实体:UserProfile

定义实体:

import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from 'typeorm';@Entity()
export class User {@PrimaryGeneratedColumn()id: number;@Column()name: string;@OneToOne(type => Profile, profile => profile.user)@JoinColumn()profile: Profile;
}@Entity()
export class Profile {@PrimaryGeneratedColumn()id: number;@Column()bio: string;@OneToOne(type => User, user => user.profile)user: User;
}
一对多关系

假设我们有一个 User 实体和一个 Post 实体。

定义实体:

import { Entity, Column, PrimaryGeneratedColumn, OneToMany } from 'typeorm';@Entity()
export class User {@PrimaryGeneratedColumn()id: number;@Column()name: string;@OneToMany(type => Post, post => post.author)posts: Post[];
}@Entity()
export class Post {@PrimaryGeneratedColumn()id: number;@Column()title: string;@Column()content: string;@ManyToOne(type => User, user => user.posts)author: User;
}
多对多关系

假设我们有一个 User 实体和一个 Group 实体。

定义实体:

import { Entity, Column, PrimaryGeneratedColumn, ManyToMany, JoinTable } from 'typeorm';@Entity()
export class User {@PrimaryGeneratedColumn()id: number;@Column()name: string;@ManyToMany(type => Group, group => group.users)@JoinTable()groups: Group[];
}@Entity()
export class Group {@PrimaryGeneratedColumn()id: number;@Column()name: string;@ManyToMany(type => User, user => user.groups)@JoinTable()users: User[];
}

自定义查询

TypeORM 提供了多种方式来进行自定义查询,包括使用 QueryBuilder 和原生 SQL 查询。

使用 QueryBuilder
import { getRepository } from 'typeorm';const userRepository = getRepository(User);// 查询所有用户
const users = await userRepository.find();// 查询特定条件下的用户
const usersByName = await userRepository.find({where: { name: 'Alice' }
});// 使用 QueryBuilder 进行复杂查询
const queryBuilder = userRepository.createQueryBuilder('user').where('user.name = :name', { name: 'Alice' }).leftJoinAndSelect('user.posts', 'posts').getMany();console.log(await queryBuilder);
使用原生 SQL 查询
import { getConnection } from 'typeorm';const result = await getConnection().query(`SELECT * FROM users WHERE name = :name`, { name: 'Alice' });console.log(result);

事务处理

事务处理可以确保一系列操作要么全部成功,要么全部失败。TypeORM 提供了事务管理的功能。

import { getConnection } from 'typeorm';async function performTransaction() {const userRepo = getConnection().getRepository(User);const postRepo = getConnection().getRepository(Post);await getConnection().transaction(async transactionalEntityManager => {const user = new User();user.name = 'Alice';await transactionalEntityManager.save(user);const post = new Post();post.title = 'My First Post';post.content = 'This is my first post.';post.author = user;await transactionalEntityManager.save(post);});
}performTransaction().catch(error => console.error(error));

迁移管理

TypeORM 提供了迁移管理功能,可以帮助你在开发过程中轻松地管理和更新数据库结构。

创建迁移文件
typeorm migration:create -n AddEmailToUser

这会在 src/migrations 目录下创建一个新的迁移文件。

编写迁移逻辑
import {MigrationInterface, QueryRunner} from "typeorm";export class AddEmailToUser1632995728234 implements MigrationInterface {public async up(queryRunner: QueryRunner): Promise<void> {await queryRunner.query(`ALTER TABLE "users" ADD "email" varchar NOT NULL`);}public async down(queryRunner: QueryRunner): Promise<void> {await queryRunner.query(`ALTER TABLE "users" DROP COLUMN "email"`);}
}
应用迁移
typeorm migration:run

性能优化

为了提高应用性能,可以采取以下措施:

批量插入
const users = [{ name: 'Alice', email: 'alice@example.com' },{ name: 'Bob', email: 'bob@example.com' },// ...
];await userRepository.insert(users);
使用缓存

TypeORM 支持多种缓存策略,可以在一定程度上减少数据库访问次数。

import { Entity, Column, PrimaryGeneratedColumn, Cache } from 'typeorm';@Entity()
@Cache()
export class User {@PrimaryGeneratedColumn()id: number;@Column()name: string;@Column()email: string;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/429134.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python基础学习(3)

目录 一&#xff0c;函数 1&#xff0c;函数的定义 2&#xff0c;函数的参数 1&#xff0c;默认值 2&#xff0c;传参 3&#xff0c;返回值 4&#xff0c;变量的作用域 5&#xff0c;函数的调用 二&#xff0c;常用数据结构 1&#xff0c;列表 列表的定义 列表的特性…

【Geoserver使用】REST API调用(工作空间部分)

文章目录 前言一、Geoserver REST API(GeoServer Workspace)二、GeoServer Workspace接口使用1.GET请求 /workspaces2.POST请求 /workspaces3.GET请求 /workspaces/{workspaceName}4.PUT /workspaces/{workspaceName}5.DELETE /workspaces/{workspaceName} 总结 前言 根据Geos…

C++ | Leetcode C++题解之第423题从英文中重建数字

题目&#xff1a; 题解&#xff1a; class Solution { public:string originalDigits(string s) {unordered_map<char, int> c;for (char ch: s) {c[ch];}vector<int> cnt(10);cnt[0] c[z];cnt[2] c[w];cnt[4] c[u];cnt[6] c[x];cnt[8] c[g];cnt[3] c[h] - …

YOLOv10 简介

YOLOv10&#xff0c;由清华大学的研究人员基于 Ultralytics Python 包构建&#xff0c;引入了一种全新的实时目标检测方法&#xff0c;该方法解决了以往 YOLO 版本中后处理和模型架构方面的不足。通过消除非极大值抑制&#xff08;NMS&#xff09;并优化各种模型组件&#xff0…

【解决】chrome 谷歌浏览器,鼠标点击任何区域都是 Input 输入框的状态,能看到输入的光标

chrome 谷歌浏览器&#xff0c;鼠标点击任何区域都是 Input 输入框的状态&#xff0c;能看到输入的光标 今天打开电脑的时候&#xff0c;网页中任何文本的地方&#xff0c;只要鼠标点击&#xff0c;就会出现一个输入的光标&#xff0c;无论在哪个站点哪个页面都是如此。 我知道…

十四、运算放大电路

运算放大电路 1、理想运算放大器的概念。运放的输入端虚拟短路、虚拟断路之间的区别; 2、反相输入方式的运放电路的主要用途&#xff0c;以及输入电压与输出电压信号的相位 3、同相输入方式下的增益表达式(输入阻抗、输出阻抗)

Redis-01 入门和十大数据类型

Redis支持两种持久化方式&#xff1a;RDB持久化和AOF持久化。 1.RDB持久化是将Redis的数据以快照的形式保存在磁盘上&#xff0c;可以手动触发或通过配置文件设置定时触发。RDB保存的是Redis在某个时间点上的数据快照&#xff0c;可以通过恢复RDB文件来恢复数据。 2.AOF持久化…

55. QTableWidget的基本使用

1. 说明 在软件界面开发中,基本上离不开数据的展示以供客户查看一些比较关注的信息,比如公司做一个员工个人信息管理系统,需要一个界面能够展示员工个人基本信息,实现这种效果可以采用多种形式,其中比较简单的一种是使用QT提供的QTableWidget控件,这个控件已经封装了一些…

LeetCode 面试经典150题 190.颠倒二进制位

复习知识&#xff1a;正数的原码、反码、补码相同&#xff0c;负数的反码在其原码的基础上, 符号位不变&#xff0c;其余各个位取反&#xff0c;负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后1 (即在反码的基础上1)。 题目&#xff1a;颠倒给定的 32 位无符号…

Springboot3 + MyBatis-Plus + MySql + Uniapp 商品加入购物车功能实现(最新教程附源码)

Springboot3 MyBatis-Plus MySql Uniapp 商品加入购物车功能实现&#xff08;针对上一篇sku&#xff09; 1、效果展示2、后端代码2.1 model2.2 mapper server serverImpl 参照上一篇自动生成2.3 controller 3、前端代码3.1 index.js3.2 shop-info.vue3.3 ShopBottomButton.v…

计算机毕业设计hadoop+spark+hive新能源汽车销售数据分析系统 二手车销量分析 新能源汽车推荐系统 可视化大屏 汽车爬虫 机器学习

《HadoopSparkHive新能源汽车销售数据分析系统》开题报告 一、选题背景与意义 1.1 选题背景 随着全球对环境保护意识的增强和能源结构的转型&#xff0c;新能源汽车市场迅速崛起。新能源汽车的销售数据不仅反映了市场趋势和消费者偏好&#xff0c;还为企业决策、政府监管和政…

【玉米田】

题目 代码 #include <bits/stdc.h> using namespace std; typedef long long LL;const int mod 1e8; const int M 1 << 12; LL f[13][M]; int g[13]; vector<int> state; vector<int> p[M]; int n, m; bool check(int x) {return !(x & x <&…

“一屏显江山”,激光显示重构「屏中世界」

【潮汐商业评论/原创】 2024年国庆期间&#xff0c;曾感动过无数国人的舞蹈诗剧《只此青绿》改编的同名电影即将上映&#xff0c;而这一次观众们不必走进电影院&#xff0c;在家里打开官方合作的海信激光电视也能享受到同等的视听效果&#xff0c;这是激光电视在观影场景领域的…

java 获取集合a比集合b多出来的对象元素

public class OrderListEntity {/*** deprecated 对象集合的处理* param aData 集合a* param bData 集合b* return 返回集合a比集合b多出来的部分, 通过id判断*/public static List<OrderListEntity> AHasMoreThanBData(List<OrderListEntity> aData, List<Ord…

Stable Diffusion 使用详解(11)--- 场景ICON制作

目录 背景 controlNet 整体描述 Canny Lineart Depth 实际使用 AI绘制需求 绘制过程 PS打底 场景模型选择 设置提示词及绘制参数 controlnet 设置 canny 边缘 depth 深度 lineart 线稿 效果 背景 这段时间不知道为啥小伙伴似乎喜欢制作很符合自己场景的ICON。…

鸿蒙开发(HarmonyOS)组件化浅谈

众所周知&#xff0c;现在组件化在移动开发中是很常见的&#xff0c;那么组件化有哪些好处&#xff1a; 1. 提高代码复用性&#xff1a;组件化允许将应用程序的不同功能模块化&#xff0c;使得这些模块可以在不同的项目中重复使用&#xff0c;从而提高开发效率并减少重复工作。…

LabVIEW编程能力如何能突飞猛进

要想让LabVIEW编程能力实现突飞猛进&#xff0c;需要采取系统化的学习方法&#xff0c;并结合实际项目进行不断的实践。以下是一些提高LabVIEW编程能力的关键策略&#xff1a; 1. 扎实掌握基础 LabVIEW的编程本质与其他编程语言不同&#xff0c;它是基于图形化的编程方式&…

行业人工智能研究-Python自监督方式学习图像表示算法

学术界人工智能研究落后于工业界 摘要 行业或工业界在人工智能研究上超出学术界&#xff0c;并占据着大量的计算力&#xff0c;数据集和人才诱人的薪水和明朗的预期吸引大量人才离开学术界&#xff0c;涌入行业或工业界即使&#xff0c;比如Meta开源其人工智能模型&#xff0…

小程序地图展示poi帖子点击可跳转

小程序地图展示poi帖子点击可跳转 是类似于小红书地图功能的需求 缺点 一个帖子只能有一个点击事件&#xff0c;不适合太复杂的功能&#xff0c;因为一个markers只有一个回调回调中只有markerId可以使用。 需求介绍 页面有地图入口&#xff0c;点开可打开地图界面地图上展…

python:编写一个函数查找字符串中的最长公共前缀

最近在csdn网站上刷到一个题目&#xff0c;题目要求编写一个函数查找字符串中的最长公共前缀&#xff0c;题目如下&#xff1a; 给出的答案如下&#xff1a; from typing import List def longestCommonPrefix(strs:List[str]) -> str:if len(strs) 0:return i 0 #代…