Node-web04-01TypeORM

TypeORM使用

  • 基于这次commit
  • 完整代码

docker容器启动 pg

1
2
3
4
5
6
7
# 本项目根目录
docker run -v "$PWD/blog-data":/var/lib/postgresql/data -p 5432:5432 -e POSTGRES_USER=blog -e POSTGRES_HOST_AUTH_METHOD=trust -d postgres:12.2

# 如果需要密码 请这样设置
替换
-e POSTGRES_HOST_AUTH_METHOD=trust 为
-e POSTGRES_HOST_PASSWORD=123456
  • 其他命令
1
2
3
4
5
# 查看容器
docker ps -a

# 查看容器启动日志
docker logs 容器id

进入docker容器

1
docker exec -it 容器id bash

进入pg命令行

  • psql -U blog -W 登陆数据库
1
2
3
4
5
6
7
8
9
10
11
# 查看有那些数据库
\l

# 连接 blog数据库
\c blog

# 查看数据库里的表
\dt

# 丢弃表
drop table 表名

创建数据库

1
2
CREATE DATABASE [数据库名] ENCODING 'UTF8' LC_COLLATE 'en_US.utf8' LC_CTYPE 'en_US.utf8';
# 分别创建三个 blog_development、test、production

安装TypeORM

1
2
3
4
5
6
7
# 安装如下依赖

"reflect-metadata": "^0.1.13"
"typeorm": "^0.2.25"

devDependencies
"@types/node": "^14.0.6"
  • tsconfig.json 里添加两个配置
1
2
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
  • 做到这步先提交代码

typeorm使用

1
2
3
4
5
6
7
8
npx typeorm init --database postgres

# 此时会生成很多文件,他会修改我们的一些东西
# 因为 typeorm 推荐使用ts-node编译(没有内置)
# babel 和 ts-node 对TS的支持并非完全一致
# 但是 Next.js 默认用babel把ts变成js,所以 package.json的改动要撤销
# 所以我们要统一用 babel处理
# 还要撤销 .gitignore的改动

babel处理 typeorm并运行

原因已经说了,typeorm需要ts-node运行,但是nextJS使用babel转译ts的,所以我们只能统一用babel

  • 安装 @babel/cli

    1
    yarn add @babel/cli
  • 编译 typeorm的 ts文件

1
2
3
4
5
6
7
8
9
10
11
12
npx babel ./src --out-dir dist --extensions ".ts,.tsx"

# 报错 can not found @babel/core
yarn add @babel/core

# 继续运行那个命令
# 结果又报错了
SyntaxError: /Users/hjx/Desktop/demo/next-demos/next-demo-2/src/entity/User.ts: Support for the experimental syntax 'decorators-legacy' isn't currently enabled (3:1):

# google 搜索 Support for the experimental syntax 'decorators-legacy' isn't currently enabled (3:1):
# 得到答案
https://stackoverflow.com/questions/52262084/syntax-error-support-for-the-experimental-syntax-decorators-legacy-isnt-cur

新建.babelrc

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"presets": [
"next/babel"
],
"plugins": [
[
"@babel/plugin-proposal-decorators",
{
"legacy": true
}
]
]
}

typeorm默认要 ts-node支持

  • 但是 nextjs 是用 babel转译 ts
  • 所以我们要统一 使用 babel
  • 所以 typeorm的文件要编译成js运行

操作步骤

1
2
3
npx babel ./src --out-dir dist --extensions ".ts,.tsx"

node /dist/index.js

重要步骤

  • 一定一定一定要改成 false
  • 如果为true 连接数据库的时候,typeorm会自动根据 entity 目录修改数据库,
    • 假如你改了 entity 多了一些列,就会同步到表里
    • 如果是生产环境,数据要么丢了,要么脏了,就很麻烦
  • 一开始就要杜绝 sync
1
2
# 修改 ormconfig.json 的配置
"synchronize": false,

创建表

  • 创建 posts 表
  • npx typeorm migration:create -n CreatePost
    • 得到 src/migrations/{TIMESTAMP}-CreatePost.ts
    • 编写对应的 up/down函数
  • 运行 migration
    • npx babel .src --out-dir dist --extensions ".ts,.tsx"
    • npx typeorm migration:run 创建表 up操作
    • npx typeorm migration:revert drop表 down操作

解决不同平台运行多个命令问题

  • 如下命令只支持 mac/linux 用户
1
"dev": "next dev & babel -w ./src --out-dir dist --extensions .ts,.tsx"

windwos咋办

concurrently

  • 支持运行多个命令,而且支持 windows
1
"dev": "concurrently \"next dev\" \"babel -w ./src --out-dir dist --extensions .ts,.tsx\"",

创建实体

package.json

1
"entity:create": "typeorm entity:create"
  • 运行 yarn entity:create -n Post
  • 会生成 src/entity/Post.ts
  • 通过 Post 类,修改 post 表
    • @Column() 修饰器 修饰对应的列,需要你自己填写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import {Column, Entity, PrimaryGeneratedColumn} from 'typeorm';

@Entity('posts')
export class Post {
@PrimaryGeneratedColumn('increment')
id: number;
@Column('varchar')
title: string;
@Column('text')
content: string;

constructor(attributes: Partial<Post>) {
Object.assign(this, attributes);
}
}

EntityManager API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
await connection.manager.find(User,{name:'查询的名字'})
await connection.manager.create(User,{name:'', attr...})

await connection.manager.save(u1)

await connection.manager.save([u1,u2,u3])

await connection.manager.remove(u1)

await connection.manager.update(User,1,{name:'xxx'})

await connection.manager.delete(User,1)

await connection.manager.findOne(User,1)

实验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import "reflect-metadata";
import {createConnection} from "typeorm";
import {Post} from "./entity/Post";

createConnection().then(async connection => {
const posts = await connection.manager.find(Post)
console.log(posts)
const p = new Post();
p.title = 'Post 1'
p.content = '我的第一篇文章'
await connection.manager.save(p);

const post2 = await connection.manager.find(Post)
console.log(post2)

connection.close()
}).catch(error => console.log(error));

总结

  • migration 用来数据库迁移
  • entity 用 类和对象操作数据库表和行
  • connection 数据库连接
  • manager/repository
    • 两种风格的API,操作实体

使用 seed 填充数据

  • 前置操作 参考 01docker.md 内容,新建好容器,配置好数据库连接

  • 开第一个终端 yarn dev

    • 可以编译我们的 typeorm代码
  • 开第二个终端执行数据库迁移

1
2
3
4
# 创建数据库表
yarn migration:run
# revert操作
yarn migration:revert
  • 填充数据
1
2
# 项目根目录
node dist/seed.js
  • 进入docker容器内部查询
1
select * from posts;

代码