龙空技术网

超越Sequelize?GitHub标星17K的TypeORM你应该尝试一下(二)

沧海之一栗 208

前言:

今天朋友们对“js实体类”大致比较注重,看官们都想要剖析一些“js实体类”的相关知识。那么小编同时在网上网罗了一些有关“js实体类””的相关内容,希望同学们能喜欢,我们一起来了解一下吧!

写这个文章是为了整理学习思路记录自己的理解与分享。上一篇文章简单介绍了一下TypeORM是一个可以运行在浏览器、node.js环境支持javascript和typescript的对象关系映射框架。它支持mysql、Microsoft SQL Server 、 Oracle等市面上大部分数据库。并提供了许多其他的特性。

这篇文章主要介绍TypeORM的快速起步。我们的例子都是使用的typescript(TypeORM源码本来就是使用typescript写的)。

首先我们通过NPM安装TypeORM框架

npm install typeorm --save

因为会使用到typescript的装饰器,所以还需要安装reflect-metadata

npm install reflect-metadata --save

reflect-metadata需要在我们项目的入口文件导入,一般是index.ts或者app.ts,根据你自己的情况定。

import "reflect-metadata";

然后你需要安装数据库驱动,我这里使用的是mysql2

npm install mysql2 --save

同样,因为我们使用到了大量的装饰器,所以需要在tsconfig.json文件中打开以下配置

// 允许使用metadata特性"emitDecoratorMetadata": true, // 允许使用装饰器特性"experimentalDecorators": true,

一切准备工作就绪以后,我们就可以开始起步了。首先我们需要与数据库创建一个连接:


import "reflect-metadata";import { createConnection } from "typeorm";createConnection({ // 这里填写你要连接的数据库的类型 // 我这是是使用的mysql // 后面我们会详细讲起他的数据库类型 type: "mysql", // 这里是你要连接的数据库的主机的地址 host: "localhost", // 这里是你要连接的数据库的主机的端口 port: 3306, // 这里是你要连接的数据库的登陆用户名 username: "root", // 这里是你要连接的数据库的登陆密码 password: "admin", // 这里是你要连接的数据库名 database: "test", // 这里是与每一张表对应的实体类 // 我们可以指定一个路径下的所有实体类 // 根据你自己的实体类的路径填写 // 如果你使用ts-node运行的程序这个路径就要指定你ts实体类的路径 // 如果是编译成js后运行的程序这个路径就要指定编译后js实体类的路径 // 同时后缀名要变成.js entities: ["。/entity/*.ts"], // 是否每次启动程序都将数据库同步更新成最新的实体类信息 synchronize: true, // 是否打印数据库查询时生成的sql语句到控制台 logging: false}) .then(connection => { // 这里可以写实体操作相关的代码 }) .catch(error => console.log(error));

数据库连接成功之后,我们就可以定义实体类了。我们先定义一个Photo实体类:

import { Entity, Column, PrimaryGeneratedColumn } from "typeorm";// 实体类必须打上Entity装饰器// 对应着数据库里面的一张表@Entity()export class Photo { // PrimaryGeneratedColumn装饰器表示id是一个自增主键 // 也可以使用PrimaryColumn把id标示成一个普通主键 @PrimaryGeneratedColumn() id: number;	// Column装饰器表示被装饰的字段对应着表里面的一个字段	// 表字段类型默认根据类字段的类型生成,比如 string 类型对应着mysql数据库的varchar类型	// 我们也可以自己指定类型,只要是符合数据库的字段类型(根据你使用的数据库不同),比如:	// @Column({ type: 'varchar', length: 100 }) @Column() name: string; @Column() description: string; @Column() filename: string; @Column() views: number; @Column() isPublished: boolean;}

这样启动程序之后会在数据库生成对应的表:

+-------------+--------------+----------------------------+| photo |+-------------+--------------+----------------------------+| id | int(11) | PRIMARY KEY AUTO_INCREMENT || name | varchar(100) | || description | text | || filename | varchar(255) | || views | int(11) | || isPublished | boolean | |+-------------+--------------+----------------------------+

现在我们可以这样新增一条photo记录:

import { createConnection } from "typeorm";// 根据你自己的实体类路径变化import { Photo } from "./entity/Photo";createConnection(/*...*/) .then(connection => { let photo = new Photo(); photo.name = "Me and Bears"; photo.description = "I am near polar bears"; photo.filename = "photo-with-bears.jpg"; photo.views = 1; photo.isPublished = true; return connection.manager.save(photo).then(photo => { console.log("Photo has been saved. Photo id is", photo.id); }); }) .catch(error => console.log(error));

可以像这样查询photo记录:

import { createConnection } from "typeorm";// 根据你自己的实体类路径变化import { Photo } from "./entity/Photo";createConnection(/*...*/) .then(async connection => { /*...*/ let allPhotos = await photoRepository.find(); console.log("All photos from the db: ", allPhotos); let firstPhoto = await photoRepository.findOne(1); console.log("First photo from the db: ", firstPhoto); let meAndBearsPhoto = await photoRepository.findOne({ name: "Me and Bears" }); console.log("Me and Bears photo from the db: ", meAndBearsPhoto); let allViewedPhotos = await photoRepository.find({ views: 1 }); console.log("All viewed photos: ", allViewedPhotos); let allPublishedPhotos = await photoRepository.find({ isPublished: true }); console.log("All published photos: ", allPublishedPhotos); let [allPhotos, photosCount] = await photoRepository.findAndCount(); console.log("All photos: ", allPhotos); console.log("Photos count: ", photosCount); }) .catch(error => console.log(error));

可以像这样删photo记录:

uimport { createConnection } from "typeorm";// 根据你自己的实体类路径变化import { Photo } from "./entity/Photo";createConnection(/*...*/) .then(async connection => { /*...*/ let photoToRemove = await photoRepository.findOne(1); await photoRepository.remove(photoToRemove); }) .catch(error => console.log(error));

可以像这样更新photo记录:

import { createConnection } from "typeorm";// 根据你自己的实体类路径变化import { Photo } from "./entity/Photo";createConnection(/*...*/) .then(async connection => { /*...*/ let photoToUpdate = await photoRepository.findOne(1); photoToUpdate.name = "Me, my friends and polar bears"; await photoRepository.save(photoToUpdate); }) .catch(error => console.log(error));

上面在我们对单个实体的增删改查做了介绍,接下来我们来介绍一下实体关系(一对一、一对多、多对一、多对多)。

创建一对一关系。我们已经有了一个Photo实体,现在我们再创建一个PhotoMetadata实体类。PhotoMetadata与Photo类是一对一的关系。

import { Entity, Column, PrimaryGeneratedColumn, OneToOne, JoinColumn } from "typeorm";// 根据你自己的实体类路径变化import { Photo } from "./Photo";@Entity()export class PhotoMetadata { @PrimaryGeneratedColumn() id: number; @Column("int") height: number; @Column("int") width: number; @Column() orientation: string; @Column() compressed: boolean; @Column() comment: string;		// OneToOne装饰用来表明一个一对一关系	// 接收的第一个参数是一个返回关系另一方的实体类的方法	// 这个方法可以没有参数,但是我们通常都会加上一个type形参来提高可读性	// 也可以这样定义 @OneToOne(() => Photo) @OneToOne(type => Photo)	// JoinColumn装饰器可以声明这个一对一关系的外键列名	// @JoinColumn() 这样设置默认为photoId	// 后面我们会讲怎么自定义外键列名	// JoinColumn装饰器只能打在关系所有者的一方	// 也就是有外键列所在的一方 @JoinColumn() photo: Photo;}

这样运行程序之后,我们会生成一张新的表:

+-------------+--------------+----------------------------+| photo_metadata |+-------------+--------------+----------------------------+| id | int(11) | PRIMARY KEY AUTO_INCREMENT || height | int(11) | || width | int(11) | || comment | varchar(255) | || compressed | boolean | || orientation | varchar(255) | || photoId | int(11) | FOREIGN KEY |+-------------+--------------+----------------------------+

对于关系的具体操作,我们后面会详细介绍。这里我们只是介绍关系怎么定义。

接下来让我们看看怎么定义一对多、多对一关系。

我们已经有了一个Photo实体类,我们再创建一个Author实体类。假设一个 photo 有一个 author,每个 author 都可以有多个 photos。下面是一对多关系:

import { Entity, Column, PrimaryGeneratedColumn, OneToMany, JoinColumn } from "typeorm";import { Photo } from "./Photo";@Entity()export class Author { @PrimaryGeneratedColumn() id: number; @Column() name: string;		// OneToMany装饰器第一个参数和OneToOne装饰器一样	// 第二个参数是一个返回关联的实体类对应的当前实体类属性的函数	// OneToOne装饰器也可以定义第二个参数 @OneToMany(type => Photo, photo => photo.author) photos: Photo[];}

OneToOne和ManyToOne总是成对出现的,一对多关系定义好了,下面是定义多对一的方式:

import { Entity, Column, PrimaryGeneratedColumn, ManyToOne } from "typeorm";import { PhotoMetadata } from "./PhotoMetadata";import { Author } from "./Author";@Entity()export class Photo { /* ... other columns */ @ManyToOne(type => Author, author => author.photos) author: Author;}

运行程序后将生成author表并且修改phpto表:

+-------------+--------------+----------------------------+| author |+-------------+--------------+----------------------------+| id | int(11) | PRIMARY KEY AUTO_INCREMENT || name | varchar(255) | |+-------------+--------------+----------------------------+ // 在一对多和多对一关系中,外键表总是生成在多的那一方,我们可以通过// JoinColumn装饰器修改默认的外键列名,后面会介绍+-------------+--------------+----------------------------+| photo |+-------------+--------------+----------------------------+| id | int(11) | PRIMARY KEY AUTO_INCREMENT || name | varchar(255) | || description | varchar(255) | || filename | varchar(255) | || isPublished | boolean | || authorId | int(11) | FOREIGN KEY |+-------------+--------------+----------------------------+

下面我们介绍一下怎么定义多对多关系。我们需要创建一个Album实体类。假设一个 photo 可以放在多个 albums 中,每个 albums 可以包含多个 photo。

import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from "typeorm";@Entity()export class Album { @PrimaryGeneratedColumn() id: number; @Column() name: string;		// ManyToMany装饰器和OneToOne起他 @ManyToMany(type => Photo, photo => photo.albums) @JoinTable() photos: Photo[];}

现在我们有了单向的多对多关系,然后我们需要再关系的另一方也添加多对多关系

nexport class Photo { /// ... other columns @ManyToMany(type => Album, album => album.photos) albums: Album[];}

运行代码后会生成一张中间表:

+-------------+--------------+----------------------------+| album_photos_photo_albums |+-------------+--------------+----------------------------+| album_id | int(11) | PRIMARY KEY FOREIGN KEY || photo_id | int(11) | PRIMARY KEY FOREIGN KEY |+-------------+--------------+----------------------------+

至此我们将TypeORM常见的关系都介绍了,更具体的操作,我们会在后面介绍。这篇文章只是一个快速启动TypeORM的学习记录。是为了记录我的学习思路和理解的。
后面会更详细的介绍每一步的操作。

各位兄弟们,一起加油呀!

标签: #js实体类