新聞中心
譯者 | 李睿

成都創(chuàng)新互聯(lián)公司是專業(yè)的綠春網站建設公司,綠春接單;提供成都網站建設、網站建設,網頁設計,網站設計,建網站,PHP網站建設等專業(yè)做網站服務;采用PHP框架,可快速的進行綠春網站開發(fā)網頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網站,專業(yè)的做網站團隊,希望更多企業(yè)前來合作!
審校 | 重樓
Prisma是一個流行的對象關系映射(ORM)工具,用于服務器端的JavaScript和TypeScript。其核心目的是簡化和自動化數據在存儲和應用程序代碼之間的移動方式。Prisma支持廣泛的數據存儲,并為數據持久性提供了一個強大而靈活的抽象層。通過這個代碼優(yōu)先之旅,可以了解Prisma及其一些核心功能。
JavaScript的ORM層
對象關系映射(ORM)是由Java中的Hibernate框架首創(chuàng)的。對象-關系映射的最初目標是克服Java類和RDBMS表之間所謂的阻抗不匹配。從這個想法中產生了更廣泛的應用程序通用持久層的概念。Prisma是Java ORM層的一個基于JavaScript的現代進化。
Prisma支持一系列SQL數據庫,并已擴展到包括NoSQL數據存儲MongoDB。無論數據存儲的類型如何,它們的首要目標都是:為應用程序提供處理數據持久性的標準化框架。
域模型
以下將使用一個簡單的域模型來查看數據模型中的幾種關系:多對一、一對多和多對多 (在這里忽略一對一,因為與多對一非常相似) 。
Prisma使用模型定義(模式)作為應用程序和數據存儲之間的樞紐。在構建應用程序時,將在這里采用的一種方法是從這個定義開始,然后從中構建代碼。Prisma自動將模式應用于數據存儲。
Prisma模型定義格式不難理解,可以使用圖形工具Prismbuilder來創(chuàng)建一個模型。而模型將支持協(xié)作的想法開發(fā)應用程序,因此將有用戶(User)、想法(Idea)和標簽(Tag)模型。一個用戶可以有多個想法(一對多),為一個想法提供一個用戶,而所有者(Owner)則有多個想法(多對一)。想法和標簽形成了多對多的關系。清單1顯示了模型定義。
清單1.Prisma中的模型定義
datasource db {
provider = "sqlite"
url = "file:./dev.db"
}
generator client {
provider = "prisma-client-js"
}
model User {
id Int @id @default(autoincrement())
name String
email String @unique
ideas Idea[]
}
model Idea {
id Int @id @default(autoincrement())
name String
description String
owner User @relation(fields: [ownerId], references: [id])
ownerId Int
tags Tag[]
}
model Tag {
id Int @id @default(autoincrement())
name String @unique
ideas Idea[]清單1包括一個數據源定義(一個簡單的SQLite數據庫,Prisma為了開發(fā)目的將其包含在內)和一個客戶端定義,“生成器客戶端”設置為Prisma-client-js。后者意味著Prisma將生成一個JavaScript客戶端,應用程序可以使用它與定義創(chuàng)建的映射進行交互。
至于模型定義,需要注意每個模型都有一個id字段,并且正在使用Prisma @default(autoincrement())注釋來獲得一個自動遞增的整數id。
為了創(chuàng)建從用戶(User)到想法(Idea)的關系,采用數組括號引用Idea類型:Idea[]。這句話的意思是:給一些用戶的想法。在關系的另一端,為想法(Idea)提供一個用戶(User): owner User @relation(字段:[ownerId],引用:[id])。
除了關系和鍵ID字段之外,字段定義也很簡單;字符串對應字符串,等等。
創(chuàng)建項目
在這里將使用一個簡單的項目來使用Prisma的功能。第一步是創(chuàng)建一個新的Node.js項目并向其添加依賴項。之后,可以添加清單1中的定義,并使用它來處理Prisma內置SQLite數據庫的數據持久性。
要啟動應用程序,將創(chuàng)建一個新目錄,初始化一個npm項目,并安裝依賴項,如清單2所示。
清單2.創(chuàng)建應用程序
mkdir iw-prisma
cd iw-prisma
npm init -y
npm install express @prisma/client body-parser
mkdir prisma
touch prisma/schema.prisma現在,在prisma/schema上創(chuàng)建一個文件。并添加清單1中的定義。接下來,告訴Prisma為SQLite準備一個模式,如清單3所示。
清單3.設置數據庫
npx prisma migrate dev --name init
npx prisma migrate deploy清單3告訴Prisma“遷移”數據庫,這意味著將模式更改從Prisma定義應用到數據庫本身。dev標志告訴Prisma使用開發(fā)概要文件,而--name為更改提供了一個任意名稱。deploy標志告訴prisma應用更改。
使用數據
現在,允許在Express.js中使用RESTful端點創(chuàng)建用戶??梢栽谇鍐?中看到服務器的代碼,它位于inw -prisma/server.js文件中。清單4是普通的Express代碼,但是由于有了Prisma,可以用最少的精力對數據庫做很多工作。
清單4.Express代碼
const express = require('express');
const bodyParser = require('body-parser');
const { PrismaClient } = require('@prisma/client');
const prisma = new PrismaClient();
const app = express();
app.use(bodyParser.json());
const port = 3000;
app.listen(port, () => {
console.log(`Server is listening on port ${port}`);
});
// Fetch all users
app.get('/users', async (req, res) => {
const users = await prisma.user.findMany();
res.json(users);
});
// Create a new user
app.post('/users', async (req, res) => {
const { name, email } = req.body;
const newUser = await prisma.user.create({ data: { name, email } });
res.status(201).json(newUser);
});目前,只有兩個端點,/usersGET用于獲取所有用戶的列表,/userPOST用于添加它們。通過分別調用Prisma.user.findMany()和Prisma.uuser.create(),可以看到可以多么容易地使用Prisma客戶端來處理這些用例。
不帶任何參數的findMany()方法將返回數據庫中的所有行。create()方法接受一個對象,該對象帶有一個數據字段,其中包含新行的值(在本例中是名稱和電子郵件—記住Prisma將自動創(chuàng)建一個唯一的ID)。
現在可以使用:node server.js運行服務器。
使用CURL進行測試
以下使用CURL測試端點,如清單5所示。
清單5.使用CURL嘗試端點
$ curl http://localhost:3000/users
[]
$ curl -X POST -H "Content-Type: application/json" -d '{"name":"George Harrison","email":"george.harrison@example.com"}' http://localhost:3000/users
{"id":2,"name":"John Doe","email":"john.doe@example.com"}{"id":3,"name":"John Lennon","email":"john.lennon@example.com"}{"id":4,"name":"George Harrison","email":"george.harrison@example.com"}
$ curl http://localhost:3000/users
[{"id":2,"name":"John Doe","email":"john.doe@example.com"},{"id":3,"name":"John Lennon","email":"john.lennon@example.com"},{"id":4,"name":"George Harrison","email":"george.harrison@example.com"}]清單5顯示了獲取所有用戶并找到一個空集,然后添加用戶,再獲取填充的集。
接下來添加一個端點,它允許創(chuàng)建想法并將它們與用戶關聯(lián)起來,如清單6所示。
清單6. User ideas POST endpoint
app.post('/users/:userId/ideas', async (req, res) => {
const { userId } = req.params;
const { name, description } = req.body;
try {
const user = await prisma.user.findUnique({ where: { id: parseInt(userId) } });
if (!user) {
return res.status(404).json({ error: 'User not found' });
}
const idea = await prisma.idea.create({
data: {
name,
description,
owner: { connect: { id: user.id } },
},
});
res.json(idea);
} catch (error) {
console.error('Error adding idea:', error);
res.status(500).json({ error: 'An error occurred while adding the idea' });
}
});
app.get('/userideas/:id', async (req, res) => {
const { id } = req.params;
const user = await prisma.user.findUnique({
where: { id: parseInt(id) },
include: {
ideas: true,
},
});
if (!user) {
return res.status(404).json({ message: 'User not found' });
}
res.json(user);
});在清單6中有兩個端點。第一個允許使用POST在/users/:userId/ideas添加一個想法。它需要做的第一件事是使用prism .user. findunique()通過ID恢復用戶。這個方法用于根據傳入的標準在數據庫中查找單個實體。在本例中,希望用戶具有來自請求的ID,因此使用:{where:{ID:prseInt(userId)}}。
一旦有了用戶,就使用prisma.idea.create來創(chuàng)建一個新的想法。這就像創(chuàng)建用戶時一樣,但現在有了一個關系字段。Prisma可以創(chuàng)建新想法和用戶之間的關聯(lián):owner:{connect:{id:user.id}}。
第二個端點是/userideas/:id的GET。這個端點的目的是獲取用戶ID并返回用戶,包括他們的想法。可以看到與findUnique調用一起使用的where子句,以及include修飾符。這里使用修飾符來告訴Prisma包含相關的想法。如果沒有這一點,就不會包含這些想法,因為Prisma默認使用延遲加載關聯(lián)獲取策略。
要測試新的端點,可以使用清單7中所示的CURL命令。
清單7.用于測試端點的CURL
$ curl -X POST -H "Content-Type: application/json" -d '{"name":"New Idea", "description":"Idea description"}' http://localhost:3000/users/3/ideas
$ curl http://localhost:3000/userideas/3
{"id":3,"name":"John Lennon","email":"john.lennon@example.com","ideas":[{"id":1,"name":"New Idea","description":"Idea description","ownerId":3},{"id":2,"name":"New Idea","description":"Idea description","ownerId":3}]}能夠添加想法并用它們恢復用戶。
帶標簽的多對多
現在添加端點來處理多對多關系中的標簽。在清單8中,處理標簽的創(chuàng)建,并將標簽(Tag)和想法(Ideas)關聯(lián)起來。
清單8.添加和顯示標簽
// create a tag
app.post('/tags', async (req, res) => {
const { name } = req.body;
try {
const tag = await prisma.tag.create({
data: {
name,
},
});
res.json(tag);
} catch (error) {
console.error('Error adding tag:', error);
res.status(500).json({ error: 'An error occurred while adding the tag' });
}
});
// Associate a tag with an idea
app.post('/ideas/:ideaId/tags/:tagId', async (req, res) => {
const { ideaId, tagId } = req.params;
try {
const idea = await prisma.idea.findUnique({ where: { id: parseInt(ideaId) } });
if (!idea) {
return res.status(404).json({ error: 'Idea not found' });
}
const tag = await prisma.tag.findUnique({ where: { id: parseInt(tagId) } });
if (!tag) {
return res.status(404).json({ error: 'Tag not found' });
}
const updatedIdea = await prisma.idea.update({
where: { id: parseInt(ideaId) },
data: {
tags: {
connect: { id: tag.id },
},
},
});
res.json(updatedIdea);
} catch (error) {
console.error('Error associating tag with idea:', error);
res.status(500).json({ error: 'An error occurred while associating the tag with the idea' });
}
});在這里增加了兩個端點。用于添加標簽的POST端點與前面的示例很相似。在清單8中,還添加了POST端點,用于將想法與標簽關聯(lián)起來。
為了將一個想法(Idea)和一個標簽(Tag)關聯(lián)起來,利用了模型定義中的多對多映射。通過ID抓取想法和標簽,并使用關聯(lián)(Connect)字段將它們相互聯(lián)系起來。現在,想法在它的標簽集合中有標簽ID,反之亦然。多對多關聯(lián)允許最多兩個一對多關系,每個實體指向另一個實體。在數據存儲中,這需要創(chuàng)建一個“查找表”(或交叉引用表),但Prisma會處理這個問題,只需要與實體本身交互。
多對多特性的最后一步是允許通過標簽找到想法,并在想法上找到標簽??梢栽谇鍐?中看到模型的這一部分。(需要注意的是,為了簡潔起見,刪除了一些錯誤。)
清單9.通過想法找到標簽,通過標簽找到想法
// Display ideas with a given tag
app.get('/ideas/tag/:tagId', async (req, res) => {
const { tagId } = req.params;
try {
const tag = await prisma.tag.findUnique({
where: {
id: parseInt(tagId)
}
});
const ideas = await prisma.idea.findMany({
where: {
tags: {
some: {
id: tag.id
}
}
}
});
res.json(ideas);
} catch (error) {
console.error('Error retrieving ideas with tag:', error);
res.status(500).json({
error: 'An error occurred while retrieving the ideas with the tag'
});
}
});
// tags on an idea:
app.get('/ideatags/:ideaId', async (req, res) => {
const { ideaId } = req.params;
try {
const idea = await prisma.idea.findUnique({
where: {
id: parseInt(ideaId)
}
});
const tags = await prisma.tag.findMany({
where: {
ideas: {
some: {
id: idea.id
}
}
}
});
res.json(tags);
} catch (error) {
console.error('Error retrieving tags for idea:', error);
res.status(500).json({
error: 'An error occurred while retrieving the tags for the idea'
});
}
});
這里有兩個端點:/ideas/tag/:tagId和/ideatags/:ideaId。它們的工作原理非常相似,可以為給定的標簽ID找到想法。從本質上來說,查詢就像一對多關系中的查詢一樣,Prisma處理查找表的遍歷。例如,為了找到一個想法的標簽,可以使用tag.findMany 方法,其中有一個where子句查找具有相關ID的想法,如清單10所示。
清單10.測試標簽概念的多對多關系
$ curl -X POST -H "Content-Type: application/json" -d '{"name":"Funny Stuff"}' http://localhost:3000/tags
$ curl -X POST http://localhost:3000/ideas/1/tags/2
{"idea":{"id":1,"name":"New Idea","description":"Idea description","ownerId":3},"tag":{"id":2,"name":"Funny Stuff"}}
$ curl localhost:3000/ideas/tag/2
[{"id":1,"name":"New Idea","description":"Idea description","ownerId":3}]
$ curl localhost:3000/ideatags/1
[{"id":1,"name":"New Tag"},{"id":2,"name":"Funny Stuff"}]
結論
雖然在這里涉及一些CRUD和關系基礎知識,但Prisma的能力遠不止于此。它提供了級聯(lián)操作(如級聯(lián)刪除)、獲取策略(允許微調從數據庫返回對象的方式)、事務、查詢和篩選API等功能。Prisma還允許根據模型遷移數據庫模式。此外,它通過在框架中抽象所有數據庫客戶機工作,使應用程序與數據庫無關。
Prisma以定義和維護模型定義為代價,為用戶提供了許多便利和功能。因此人們很容易理解這個用于JavaScript的ORM工具是開發(fā)人員一個熱門選擇的原因。
原文標題:Prisma.js:Code-first ORM in JavaScript,作者:Matthew Tyson
標題名稱:Prisma.js:JavaScript中的代碼優(yōu)先ORM
瀏覽地址:http://www.5511xx.com/article/dhchcgi.html


咨詢
建站咨詢
