建议收藏|一文带你读懂 Prisma 的使用
ORM(Object relational mappers) 的含义是,将数据模型与 Object 建立强力的映射关系,这样我们对数据的增删改查可以转换为操作 Object(对象)。
Prisma 是一个现代 Nodejs ORM 库,根据 Prisma 官方文档 可以了解这个库是如何设计与使用的。
概述
Prisma 提供了大量工具,包括 Prisma Schema、Prisma Client、Prisma Migrate、Prisma CLI、Prisma Studio 等,其中最核心的两个是 Prisma Schema 与 Prisma Client,分别是描述应用数据模型与 Node 操作 API。
与一般 ORM 完全由 Class 描述数据模型不同,Primsa 采用了一个全新语法 Primsa Schema 描述数据模型,再执行 prisma generate
产生一个配置文件存储在 node_modules/.prisma/client
中,Node 代码里就可以使用 Prisma Client 对数据增删改查了。
Prisma Schema
Primsa Schema 是在最大程度贴近数据库结构描述的基础上,对关联关系进行了进一步抽象,并且背后维护了与数据模型的对应关系,下图很好的说明了这一点:
<img width=400 src="https://z3.ax1x.com/2021/10/17/5YwZoF.png">
可以看到,几乎与数据库的定义一模一样,唯一多出来的 posts
与 author
其实是弥补了数据库表关联外键中不直观的部分,将这些外键转化为实体对象,让操作时感受不到外键或者多表的存在,在具体操作时再转化为 join 操作。下面是对应的 Prisma Schema:
datasource db {provider = "postgresql"url = env("DATABASE_URL")
}generator client {provider = "prisma-client-js"
}model Post {id Int @id @default(autoincrement())title Stringcontent String? @map("post_content")published Boolean @default(false)author User? @relation(fields: [authorId], references: [id])authorId Int?
}model User {id Int @id @default(autoincrement())email String @uniquename String?posts Post[]
}
datasource db
申明了链接数据库信息;generator client
申明了使用 Prisma Client 进行客户端操作,也就是说 Prisma Client 其实是可以替换实现的;model
是最核心的模型定义。
在模型定义中,可以通过 @map
修改字段名映射、@@map
修改表名映射,默认情况下,字段名与 key 名相同:
model Comment {title @map("comment_title")@@map("comments")
}
字段由下面四种描述组成:
- 字段名。
- 字段类型。
- 可选的类型修饰。
- 可选的属性描述。
model Tag {name String? @id
}
在这个描述里,包含字段名 name
、字段类型 String
、类型修饰 ?
、属性描述 @id
。
字段类型
字段类型可以是 model,比如关联类型字段场景:
model Post {id Int @id @default(autoincrement())// Other fieldscomments Comment[] // A post can have many comments
}model Comment {id Int// Other fieldsPost Post? @relation(fields: [postId], references: [id]) // A comment can have one postpostId Int?
}
关联场景有 1v1, nv1, 1vn, nvn 四种情况,字段类型可以为定义的 model 名称,并使用属性描述 @relation
定义关联关系,比如上面的例子,描述了 Commenct
与 Post
存在 nv1 关系,并且 Comment.postId
与 Post.id
关联。
字段类型还可以是底层数据类型,通过 @db.
描述,比如:
model Post {id @db.TinyInt(1)
}
对于 Prisma 不支持的类型,还可以使用 Unsupported
修饰:
model Post {someField Unsupported("polygon")?
}
这种类型的字段无法通过 ORM API 查询,但可以通过 queryRaw
方式查询。queryRaw
是一种 ORM 对原始 SQL 模式的支持,在 Prisma Client 会提到。
类型修饰
类型修饰有 ?
[]
两种语法,比如:
model User {name String?posts Post[]
}
分别表示可选与数组。
属性描述
属性描述有如下几种语法:
model User {id Int @id @default(autoincrement())isAdmin Boolean @default(false)email String @unique@@unique([firstName, lastName])
}
@id
对应数据库的 PRIMARY KEY。
@default
设置字段默认值,可以联合函数使用,比如 @default(autoincrement())
,可用函数包括 autoincrement()
、dbgenerated()
、cuid()
、uuid()
、now()
,还可以通过 dbgenerated
直接调用数据库底层的函数,比如 dbgenerated("gen_random_uuid()")
。
@unique
设置字段值唯一。
@relation
设置关联,上面已经提到过了。
@map
设置映射,上面也提到过了。
@updatedAt
修饰字段用来存储上次更新时间,一般是数据库自带的能力。
@ignore
对 Prisma 标记无效的字段。
所有属性描述都可以组合使用,并且还存在需对 model 级别的描述,一般用两个 @
描述,包括 @@id
、@@unique
、@@index
、@@map
、@@ignore
。
ManyToMany
Prisma 在多对多关联关系的描述上也下了功夫,支持隐式关联描述:
model Post {id Int @id @default(autoincrement())categories Category[]
}model Category {id Int @id @default(autoincrement())posts Post[]
}
看上去很自然,但其实背后隐藏了不少实现。数据库多对多关系一般通过第三张表实现,第三张表会存储两张表之间外键对应关系,所以如果要显式定义其实是这样的:
model Post {id Int @id @default(autoincrement())categories CategoriesOnPosts[]
}model Category {id Int @id @default(autoincrement())posts CategoriesOnPosts[]
}model CategoriesOnPosts {post Post @relation(fields: [postId], references: [id])postId Int // relation scalar field (used in the `@relation` attribute above)category Category @relation(fields: [categoryId], references: [id])categoryId Int // relation scalar field (used in the `@relation` attribute above)assignedAt DateTime @default(now())assignedBy String@@id([postId, categoryId])
}
背后生成如下 SQL:
CREATE TABLE "Category" (id SERIAL PRIMARY KEY
);
CREATE TABLE "Post" (id SERIAL PRIMARY KEY
);
-- Relation table + indexes -------------------------------------------------------
CREATE TABLE "CategoryToPost" ("categoryId" integer NOT NULL,"postId" integer NOT NULL,"assignedBy" text NOT NULL"assignedAt" timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,FOREIGN KEY ("categoryId") REFERENCES "Category"(id),FOREIGN KEY ("postId") REFERENCES "Post"(id)
);
CREATE UNIQUE INDEX "CategoryToPost_category_post_unique" ON "CategoryToPost"("categoryId" int4_ops,"postId" int4_ops);
Prisma Client
描述好 Prisma Model 后,执行 prisma generate
,再利用 npm install @prisma/client
安装好 Node 包后,就可以在代码里操作 ORM 了:
import { PrismaClient } from '@prisma/client'const prisma = new PrismaClient()
CRUD
使用 create
创建一条记录:
const user = await prisma.user.create({data: {email: 'elsa@prisma.io',name: 'Elsa Prisma',},
})
使用 createMany
创建多条记录:
const createMany = await prisma.user.createMany({data: [{ name: 'Bob', email: 'bob@prisma.io' },{ name: 'Bobo', email: 'bob@prisma.io' }, // Duplicate unique key!{ name: 'Yewande', email: 'yewande@prisma.io' },{ name: 'Angelique', email: 'angelique@prisma.io' },],skipDuplicates: true, // Skip 'Bobo'
})
使用 findUnique
查找单条记录:
const user = await prisma.user.findUnique({where: {email: 'elsa@prisma.io',},
})
对于联合索引的情况:
model TimePeriod {year Intquarter Inttotal Decimal@@id([year, quarter])
}
需要再嵌套一层由 _
拼接的 key:
const timePeriod = await prisma.timePeriod.findUnique({where: {year_quarter: {quarter: 4,year: 2020,},},
})
使用 findMany
查询多条记录:
const users = await prisma.user.findMany()
可以使用 SQL 中各种条件语句,语法如下:
const users = await prisma.user.findMany({where: {role: 'ADMIN',},include: {posts: true,},
})
使用 update
更新记录:
const updateUser = await prisma.user.update({where: {email: 'viola@prisma.io',},data: {name: 'Viola the Magnificent',},
})
使用 updateMany
更新多条记录:
const updateUsers = await prisma.user.updateMany({where: {email: {contains: 'prisma.io',},},data: {role: 'ADMIN',},
})
使用 delete
删除记录:
const deleteUser = await prisma.user.delete({where: {email: 'bert@prisma.io',},
})
使用 deleteMany
删除多条记录:
const deleteUsers = await prisma.user.deleteMany({where: {email: {contains: 'prisma.io',},},
})
使用 include
表示关联查询是否生效,比如:
const getUser = await prisma.user.findUnique({where: {id: 19,},include: {posts: true,},
})
这样就会在查询 user
表时,顺带查询所有关联的 post
表。关联查询也支持嵌套:
const user = await prisma.user.findMany({include: {posts: {include: {categories: true,},},},
})
筛选条件支持 equals
、not
、in
、notIn
、lt
、lte
、gt
、gte
、contains
、search
、mode
、startsWith
、endsWith
、AND
、OR
、NOT
,一般用法如下:
const result = await prisma.user.findMany({where: {name: {equals: 'Eleanor',},},
})
这个语句代替 sql 的 where name="Eleanor"
,即通过对象嵌套的方式表达语义。
Prisma 也可以直接写原生 SQL:
const email = 'emelie@prisma.io'
const result = await prisma.$queryRaw(Prisma.sql`SELECT * FROM User WHERE email = ${email}`
)
中间件
Prisma 支持中间件的方式在执行过程中进行拓展,看下面的例子:
const prisma = new PrismaClient()// Middleware 1
prisma.$use(async (params, next) => {console.log(params.args.data.title)console.log('1')const result = await next(params)console.log('6')return result
})// Middleware 2
prisma.$use(async (params, next) => {console.log('2')const result = await next(params)console.log('5')return result
})// Middleware 3
prisma.$use(async (params, next) => {console.log('3')const result = await next(params)console.log('4')return result
})const create = await prisma.post.create({data: {title: 'Welcome to Prisma Day 2020',},
})const create2 = await prisma.post.create({data: {title: 'How to Prisma!',},
})
输出如下:
Welcome to Prisma Day 2020
1
2
3
4
5
6
How to Prisma!
1
2
3
4
5
6
可以看到,中间件执行顺序是洋葱模型,并且每个操作都会触发。我们可以利用中间件拓展业务逻辑或者进行操作时间的打点记录。
如果你想开发小程序或者了解更多小程序的内容,可以通过专业开发公司,来帮助你实现开发需求:厦门在乎科技-专注厦门小程序定制开发、APP开发、网站开发、H5小游戏开发
建议收藏|一文带你读懂 Prisma 的使用相关推荐
- 一文带你读懂HTTP协议的前世今生
点击上方蓝字关注我们 HTTP,Hypertext Transfer Protocol,超文本协议,是在万维网上传输文件(如文本.图形图像.声音.视频和其他多媒体文件)的规则集.如果web用户打开他们 ...
- DNN、RNN、CNN.…..一文带你读懂这些绕晕人的名词
DNN.RNN.CNN.-..一文带你读懂这些绕晕人的名词 https://mp.weixin.qq.com/s/-A9UVk0O0oDMavywRGIKyQ 「撞脸」一直都是娱乐圈一大笑梗. 要是买 ...
- 一文带您读懂FCC、CE、CCC认证的区别
一文带您读懂FCC.CE.CCC认证的区别 参考资料:https://3g.k.sohu.com/t/n411629823 FCC认证,CE认证,CCC认证是产品认证中比较常见的几个认证,前两者经常有 ...
- 机器学习中为什么需要梯度下降_机器学习101:一文带你读懂梯度下降
原标题 | Machine Learning 101: An Intuitive Introduction to Gradient Descent 作者 | Thalles Silva 译者 | 汪鹏 ...
- 用程序员计算机算进制,一文带你读懂计算机进制
hi,大家好,我是开发者FTD.在我们的学习和工作中少不了与进制打交道,从出生开始上学,最早接触的就是十进制,当大家学习和使用计算机时候,我们又接触到了二进制.八进制以及十六进制.那么大家对进制的认识 ...
- 一文带你读懂“经典TRIZ”
本文承接上文<一文带第读懂TRIZ>,下面开始看第二个问题:什么是"经典TRIZ"? 很多书里都有对TRIZ的产生与发展的描述. 我个人在看了很多的书和文献以后,认为: ...
- 简单一文带你读懂Java变量的作用和三要素
Java变量的作用 不只是java,在其他的编程语言中变量的作用只有一个:存储值(数据) 在java中,变量本质上是一块内存区域,数据存储在java虚拟机(JVM)内存中 变量的三要素 变量的三要素分 ...
- 一文带你读懂感知机的前世今生(上)
一文带你读懂感知机的前世今生 前言 男女不分 什么是神经元 M-P神经元 全或无定律 McCulloch和Pitts 一种高度简化的模型 MP神经元和真值表 MP神经元的几何理解 后记 参考 前言 男 ...
- 《一文带你读懂:云原生时代业务监控》
点击上方蓝字关注我们! 对业务来说,完备的应用健康性和数据指标的监控非常重要,通过采集准确的监控指标.配置合理的告警机制,我们能够提前或者尽早发现问题,并做出响应.解决问题,进而保证产品的稳定性,提升 ...
- au加载默认的输入和输出设备失败_一文带你读懂 C/C++ 语言输入输出流与缓存区...
(给CPP开发者加星标,提升C/C++技能) 作者:技术让梦想更伟大 / 李肖遥 (本文来自作者投稿) 前言 有没有发现,基本上所有的C语言入门书籍,或者是我们的教程里面,第一个C语言程序实体,都是& ...
最新文章
- 使用现代C++如何避免bugs(下)
- #每天一种设计模式# 观察者模式
- 【运筹学】线性规划数学模型 ( 知识点回顾 | 可行解 | 最优解 | 阶梯型矩阵 | 阶梯型矩阵向量 | 基 | 基向量 | 基变量 | 非基变量 )
- matplotlib可视化必知必会富文本绘制方法
- 双时隙的工作原理_智能天线工作原理是什么 智能天线技术发展介绍【图文】...
- python七段数码管绘制单个数字_#Python语言程序设计Demo - 七段数码管绘制
- mysql用编号查询密码,【mysql中退出当前数据库】
- android app攻击与防范论文,基于Android平台的应用程序安全保护研究与应用
- VMware ubuntu16安装
- Vue自定义插件方法大全
- 【机器学习笔记】使用lightgbm画并保存Feature Importance
- IIS连接oralce数据提示“System.Data.OracleClient 需要 Oracle 客户端软件 8.1.7 或更高版本”...
- springboot办公OA考勤请假系统java
- 机器人动力学(雅克比)
- 二元二次不定方程(佩尔方程)
- git和Github
- error: #79: expected a type specifier
- 打包docker镜像,推送远程服务器,部署到k8s步骤
- Wireline SerDes,高速信号的均衡技术
- 《区块链助力粤港澳大湾区一体化发展报告(2022)》发布
热门文章
- 重学css 0x3 CSS效果
- Java 的 FileInputStream 是否需要 close
- 运行3项目显示Module ‘“vue“‘ has no exported member ‘xxxx‘. Did you mean ‘Xxxx‘? TS2305: Module ‘“…/…/node_
- ssm 项目中引用 百度bae的sdk 安装jar
- 【支持升级官方最新版】西部数码主机代理系统模板源码IDC网站源码虚拟主机代理管理系统
- 怎么使用关键词获取视频列表 API
- DataV-组件配置
- 为招商手机银行点个赞!
- 觉得为时已晚的时候,恰恰是最早的时候。
- 对于von Mises distribution(冯·米塞斯分布)的一点心得