首页 » 排名链接 » 第1讲 TypeORM开发环境的搭建(数据库搭建环境开发实体)

第1讲 TypeORM开发环境的搭建(数据库搭建环境开发实体)

乖囧猫 2024-11-14 06:11:17 0

扫一扫用手机浏览

文章目录 [+]

「现在,请搜索微信小程序「奥科领航信息技术 」,让我们一起深入代码的世界,探索无限可能!

TypeORM 是一个非常流行的 ORM(对象关系映射)框架,它可以在 TypeScript 和 JavaScript (ES6+) 环境中使用。
TypeORM 旨在与 TypeScript 结合得天衣无缝,利用 TypeScript 的高级特性如装饰器和异步函数来简化数据库交互操作。

主要特性:

第1讲 TypeORM开发环境的搭建(数据库搭建环境开发实体) 排名链接
(图片来自网络侵删)
支持多种数据库:TypeORM 支持多种 SQL 数据库,包括 MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, 以及更多。
这为开发者提供了灵活性,可以根据项目需求选择合适的数据库。
Active Record 和 Data Mapper 模式:TypeORM 提供了两种模式来管理数据实体。
Active Record 模式允许实体自己保存、加载和删除等操作;Data Mapper 模式则通过仓库(Repository)或管理器(Manager)来处理这些操作。
自动数据库模式同步:TypeORM 可以自动创建数据库表和字段,根据实体类的变更自动同步数据库模式,这使得数据库维护变得简单。
高级查询能力:通过QueryBuilder,开发者可以构建复杂的SQL查询,同时保持代码的可读性和可维护性。
事务支持:TypeORM 提供了事务支持,可以执行多个数据库操作作为一个单一的工作单元来处理,确保数据的一致性和完整性。
装饰器和实体关系:TypeORM 使用装饰器来定义实体和数据库表之间的关系,如一对一、一对多、多对一和多对多关系。

开始使用 TypeORM 的最快方法是使用其 CLI 命令生成启动项目。
只有在 Node.JS 应用程序中使用 TypeORM 时,此操作才有效。

一、快速开始1.1 安装TypeORM

全局安装 TypeORM:

cnpm install typeorm -g

1.2 创建项目

切换到要创建新项目的目录并运行命令:

typeorm init --name ch01 --database mysql

其中:

name是项目的名称,database是你将使用的数据库。
数据库可以是以下值之一:mysql, mariadb, postgres, sqlite, mssql, oracle, mongodb, cordova, react-native, expo, nativescript。

此命令将在ch01目录中生成一个包含以下文件的新项目:

MyProject├── src // TypeScript 代码│ ├── entity // 存储实体(数据库模型)的位置│ │ └── User.ts // 示例 entity│ ├── migration // 存储迁移的目录│ └── index.ts // 程序执行主文件├── .gitignore // gitignore文件├── ormconfig.json // ORM和数据库连接配置├── package.json // node module 依赖├── README.md // 简单的 readme 文件└── tsconfig.json // TypeScript 编译选项

1.3 修改数据源配置

修改src/data-source.ts数据源配置文件,主要是修改username、password、database三个属性:

import "reflect-metadata"import { DataSource } from "typeorm"import { User } from "./entity/User"export const AppDataSource = new DataSource({type: "mysql",host: "localhost",port: 3306,username: "root",password: "123456",database: "mydb",synchronize: true,logging: false,entities: [User],})

注意:需要确保database属性指定的数据库是存在的,即先要创建好这个数据库。

1.4 运行项目

在VS Code的终端执行以下指令运行项目:

npm start

如果没有错误的话,是这个样子的:

PS E:\我的程序\S1\TypeORM\ch01> npm start> ch01@0.0.1 start> ts-node src/index.ts

切换到数据库,可以看到数据表已经自动创建好,并且成功的插入了两条记录:

打开浏览器,输入:

http://localhost:3001/users

是不是so easy?

如果用npm start指令来运行项目的话,不能实现热加载,即每次代码做了变动,都要ctrl + c停止服务,然后再重新启动,挻麻烦的。
可以用nodemon进行简化。

先全局安装nodemon:

cnpm i nodemon -g

再用nodemon运行入口文件src/index.ts:

nodemon src/index.ts

二、代码解读2.1 创建模型

使用数据库从创建表开始。
如何告诉 TypeORM 创建数据库表?答案是 - 通过模型。
应用程序中的模型即是数据库中的表。
模型也称为"实体类"。

所有的模型类存放在src/entity目录中。

src/entity/User.ts:

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"@Entity()export class User {@PrimaryGeneratedColumn()id: number@Column()firstName: string@Column()lastName: string@Column()age: number}

2.1.1 @Entity

@Entity装饰器用于将一个实体类映射成一个数据表。
默认情况下,实体类的类名就是数据表的表名(在MySQL中,表名自动变成了小写字母)。
我们知道,类名通常用名词,且是单数,但在数据库中,表名一般用复数。
那如何将单数形式的类名映射成复数形式的表名呢?

@Entity({name: "users"})

2.1.2 @PrimaryGeneratedColumn

每个实体必须至少有一个主键列。
这是必须的,你无法避免。
要使列成为主键,你需要使用@PrimaryColumn装饰器。
假设你希望 id 列自动生成,是自增长的,那么需要使用@PrimaryGeneratedColumn装饰器:

@PrimaryGeneratedColumn()id: number

2.1.3 Column

要添加数据库列,你只需要将要生成的实体属性加上@Column装饰器。
数据库中的列类型是根据你使用的属性类型推断的,例如: number将被转换为int,string将转换为varchar(255),boolean转换为bool等。
但你也可以通过在@Column装饰器中显式指定列类型来使用数据库支持的任何列类型:

@Column({length: 100})firstName: string@Column({length: 50})lastName: string@Column("double")age: number

2.1.4 初始值

前面所定义的属性都没有初始值,如果TypeScript的编译模式设置为严格模式的话,会报错。

(1)修改tsconfig.json,将编译模式设置为严格(第14行代码):

{"compilerOptions": {"lib": ["es5","es6"],"target": "es5","module": "commonjs","moduleResolution": "node","outDir": "./build","emitDecoratorMetadata": true,"experimentalDecorators": true,"sourceMap": true,"strict": true}}

在严格模式下,每一个属性都需要有一个初始值。
有两种方式设置属性的初始值。

(2)在构造方法中赋初始值

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"@Entity({ name: "users" })export class User {constructor(){this.id = 0;this.firstName = "";this.lastName = "";this.age = 0}@PrimaryGeneratedColumn()id: number@Column({ length: 100 })firstName: string@Column({ length: 50 })lastName: string@Column("double")age: number}

(3)直接在属性声明时赋初始值

import { Entity, PrimaryGeneratedColumn, Column } from "typeorm"@Entity({ name: "users" })export class User {@PrimaryGeneratedColumn()id: number = 0@Column({ length: 100 })firstName: string = ""@Column({ length: 50 })lastName: string = ""@Column("double")age: number = 0}

可是,一旦开启严格模式,项目中好多地方都报错了,比如:

在开启严格模式后,TypeScript会更加严格地检查你的代码,包括模块的导入和类型声明。
错误描述中显示无法找到模块"express"的声明文件,这意味着TypeScript无法找到与该模块对应的类型定义文件(通常是以.d.ts为扩展名的文件)。
解决方法:安装类型声明文件。

cnpm install @types/express --save-dev

现在错误消失了。

2.2 配置数据源

配置数据源,主要就是配置数据库的连接信息,这项工作是在src/data-source.ts文件中完成的:

import "reflect-metadata"import { DataSource } from "typeorm"import { User } from "./entity/User"export const AppDataSource = new DataSource({type: "mysql",host: "localhost",port: 3306,username: "root",password: "123456",database: "mydb",synchronize: true,logging: false,entities: [User],migrations: [],subscribers: [],})

这里说一下synchronize和entities两个属性。

synchronize:设置synchronize的值为true,可确保同步数据库结构(开启后会自动创建或更新数据库表结构,仅在开发环境中使用)。
entities:所有需要在连接中使用的每个实体都必须加到这个属性中。
之后当我们创建更多实体时,都需要将一一它们添加到配置中的实体中,但是这不是很方便,所以我们可以设置整个目录,从中连接所有实体并在连接中使用:entities: [__dirname + "/entity/.js"]

现在我们来测试一下。
再定义一个新的模型:

import { Entity, Column, PrimaryGeneratedColumn } from "typeorm"@Entity({ name: "departments" })export class Department {@PrimaryGeneratedColumn()id: number = 0;@Column({ length: 100 })name: string = "";@Column({ length: 1000 })description: string = "";@Column("datetime")createTime: Date = new Date();}

2.3 CRUD操作2.3.1 Create

Create操作,即往表中插入记录。

创建一个新的 Department 存到数据库中。

下面的操作都是在src/index.ts文件中进行。

2.3.1.1 使得Entity Manager

Entity Manager,实体管理器,顾名思义,它可以对实体进行任何操作。

(1)方法一

import { AppDataSource } from "./data-source"import { Department } from "./entity/Department"AppDataSource.initialize().then(async () => {await AppDataSource.manager.save(AppDataSource.manager.create(Department, {name: "研发部",description: "工资很高的部门",createTime: new Date()}));console.log("ok");}).catch(error => console.log(error))

(2)方法2

let item = new Department();item.name = "财务部";item.description = "油水很多的部门";item.createTime = new Date("2001-1-1");await AppDataSource.manager.save(item);

2.3.1.2 使用Repository

现在让我们重构之前的代码,并使用Repository而不是EntityManager。
每个实体都有自己的存储库,可以处理其实体的所有操作。
当你经常处理实体时,Repository 比 EntityManager 更方便使用。

let item = new Department();item.name = "行政部";item.description = "很悠闲的部门";item.createTime = new Date("2001-1-1");let departmentRepository = AppDataSource.getRepository(Department);departmentRepository.save(item);console.log("ok");

2.3.2 Read

Read操作,即查询数据表中的记录。

先往数据表插入一些测试数据:

INSERT INTO `users` VALUES(NULL, '刘德华', '', 48),(NULL, '张学友', '', 50),(NULL, '郭富城', '', 42),(NULL, '刘青云', '', 46),(NULL, '刘德华', '', 20),(NULL, '关之琳', '', 45),(NULL, '张曼玉', '', 42);

mysql> use mydbDatabase changedmysql> select from `users`;+----+-----------+----------+-----+| id | firstName | lastName | age |+----+-----------+----------+-----+| 1 | 刘德华 | | 48 || 2 | 张学友 | | 50 || 3 | 郭富城 | | 42 || 4 | 刘青云 | | 46 || 5 | 刘德华 | | 20 || 6 | 关之琳 | | 45 || 7 | 张曼玉 | | 42 |+----+-----------+----------+-----+7 rows in set (0.00 sec)mysql>

(1)查询出所有的记录

调用find()方法,不传入任何参数,即表示查询出所有记录。

let userRepository = AppDataSource.getRepository(User);let users = await userRepository.find();console.log(users);console.log("ok");

(2)根据主键值查询

调用findOneBy()方法。

let userRepository = AppDataSource.getRepository(User);let user = await userRepository.findOneBy({ id: 1 })console.log(user);console.log("ok");

(3)查询符合条件的第一条记录

调用findOne()方法,并传入一个where条件。

let userRepository = AppDataSource.getRepository(User);let user = await userRepository.findOne({ where: { firstName: "刘德华" } });console.log(user);console.log("ok");

可以看到,只查询出了第1个刘德华。

(4)模糊查询

类似于MySQL数据库中like。

用find和Like方法。
Like区分大小写,ILike忽略大小写。

let userRepository = AppDataSource.getRepository(User);let users = await userRepository.find({ where: { firstName: ILike("张%") } });console.log(users);console.log("ok");

(5)数字大小比较

大于:MoreThan大于等于(>=):MoreThanOrEqual小于(<):LessThan小于等于(<=):LessThanOrEqual等于(==):Equal不等于(!=):Not

let userRepository = AppDataSource.getRepository(User);let users = await userRepository.find({ where: { age: MoreThan(40) } });console.log(users);

(6)多个条件的查询

示例1:查询"刘"姓且年龄大于等于48岁的用户
这是逻辑与的查询。

let userRepository = AppDataSource.getRepository(User);let users = await userRepository.find({where: {firstName: Like("刘%"),age: MoreThanOrEqual(48)}});console.log(users);

示例2:查询"张"姓或年龄大于等于48岁的用户。
这是逻辑或的查询。

let userRepository = AppDataSource.getRepository(User);let users = await userRepository.find({where: [{ firstName: Like("张%") },{ age: MoreThanOrEqual(48) }]});console.log(users);

(7)对结果进行排序

asc:升序desc:降序

let userRepository = AppDataSource.getRepository(User);let users = await userRepository.find({order: {age: "desc"}})console.log(users);

(8)查询出某个区间的记录

skip:跳过多少条take:抓取多少条

let userRepository = AppDataSource.getRepository(User);let users = await userRepository.find({order: {age: "desc"},skip: 2,take: 3})console.log(users);

2.3.3 Update

Update,即更新操作。

让我们从数据库加载出User,更新并保存到数据库:

let userRepository = AppDataSource.getRepository(User);let user = await userRepository.findOneBy({ id: 1 });if (user != null) {user.age = 18;userRepository.save(user);} else {console.log("未找到");}console.log("ok");

查询数据库,可以发现ID为1的用户的年龄变成了18。

2.3.4 Delete

Delete,即删除操作。

let userRepository = AppDataSource.getRepository(User);let user = await userRepository.findOneBy({ id: 1 });if (user != null) {userRepository.remove(user);} else {console.log("未找到");}console.log("ok");

查询数据库,可以发现ID为1的用户已经被删除了。

三、其他事项

再次审视一下数据源配置文件(src/data-source.ts):

import "reflect-metadata"import { DataSource } from "typeorm"export const AppDataSource = new DataSource({type: "mysql",host: "localhost",port: 3306,username: "root",password: "123456",database: "mydb",synchronize: false,logging: false,entities: [__dirname + "/entity/.ts"],})

其中synchronize属性的作用是什么呢?设置为true和false有何区别?

在 TypeORM 中,synchronize 属性用于指定在应用程序启动时是否自动同步数据库结构。
它的作用如下:

当 synchronize 设置为 true 时,TypeORM 会在应用程序启动时自动检查数据库结构和实体类的差异,并尝试自动同步它们。
如果数据库中不存在指定的表或列,TypeORM 会尝试创建它们。
这个过程被称为自动同步(automatic synchronization)。
如果数据库中存在与实体类不匹配的表或列,自动同步可能会删除或修改数据库中的数据,带来意外的数据丢失或改动。
因此,在生产环境中,通常不推荐使用 synchronize: true。
当 synchronize 设置为 false 时,TypeORM 不会自动检查数据库结构。
它会假定数据库结构与实体类定义一致,并且不会对数据库做任何更改。
你需要手动执行数据库迁移(migrations)来同步数据库结构或修改数据库。

因此,synchronize 的设置会影响 TypeORM 在启动应用程序时是否自动创建或修改数据库结构。
在开发阶段,使用 synchronize: true 可以方便地创建和更新表结构,但在生产环境中建议将其设置为 false,并使用数据库迁移工具来管理数据库结构的变更。

标签:

相关文章

女装(女装会员让你钻石营收)

·1、预存一定金额到会员卡中,可用于二次消费抵扣;·2、享受所有衣服的88折优惠;·3、邀请好友购买,可获得成交额的10%奖励;·...

排名链接 2024-12-07 阅读568 评论0