Wasp 数据模型入门(v0.13):Entity 实体定义、Prisma 映射与直接操作指南
2026/9/14 3:41:42 网站建设 项目流程

Wasp 数据模型入门(v0.13):Entity 实体定义、Prisma 映射与直接操作指南

【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp

Entity(实体)是 Wasp 应用数据模型的地基:一个 Entity 就对应数据库中的一个数据模型。本文基于 Wasp v0.13 版本文档 entities.md 展开,完整覆盖实体的声明语法({=psl ... psl=}内嵌 Prisma Schema Language)、wasp db migrate-dev迁移工作流、通过 Operations 与 Prisma Client 访问实体的两种方式,并结合编译器源码(Haskell 实现的 PSL 解析器与实体 AST)解释 Wasp 是如何理解你的实体定义、识别主键并支撑自动 CRUD 的。

1. Entity 与 Prisma:Wasp 数据层的底座

Wasp 用 Prisma ORM 实现全部数据库功能,并在其上覆盖一层薄薄的抽象。核心关系是:Wasp Entity 与 Prisma 的数据模型(data model)一一对应

这带来三个直接结论:

  1. 你不需要先精通 Prisma。Wasp 为 Prisma 的核心能力封装了简单 API(Operations、CRUD 等),绝大多数场景不用直接接触 Prisma Client 即可读写数据。
  2. 定义实体的唯一前置技能是 PSL(Prisma Schema Language)——Prisma 专门用于声明式定义模型的简单语言。PSL 声明式且直白,读到下文示例就能上手,无需提前系统学习。
  3. 数据库能力的边界由 Prisma 决定。需要 Wasp 没有封装的高级能力(复杂事务、原始查询等)时,可以“降级”直接拿 Prisma Client,这在 v0.13 中是被官方认可的路径。

2. 定义一个 Entity:entity Task的完整解剖

entity声明即数据库模型声明。以最常见的Task(任务)为例,v0.13 中在项目的.wasp文件(如main.wasp)中这样写:

entity Task {=psl id Int @id @default(autoincrement()) description String isDone Boolean @default(false) psl=}

逐条拆解这份声明:

  • entity Task:告诉 Wasp 我们要定义一个名为Task的实体(即数据库模型)。Wasp 会自动创建名为tasks(复数小写)的表,这一点在后续 Operations 路由生成中同样生效(详见第 5 节源码佐证)。
  • {=psl ... psl=}:Wasp 把两个psl标记之间的内容当作PSL(Prisma Schema Language)处理。也就是说,实体定义 = Wasp 的entity外壳 + 原生的 Prisma 模型字段语法,Prisma 的属性(attribute)语义在这里完整保留。

上面的 PSL 定义了tasks表的三列:

字段类型属性含义
idInt@id @default(autoincrement())主键,整型。数据库自动生成:在上一行自增 1
descriptionString任务描述,普通字符串列
isDoneBoolean@default(false)完成状态布尔列。创建时不显式设置,数据库默认置false

几个可以直接复用的 PSL 要点:

  • @id标记主键字段——Wasp 编译器对它的识别逻辑有源码级证据,见第 5 节;
  • @default(...)提供列级默认值,支持autoincrement()falsenow()uuid()等 Prisma 默认值表达式;
  • 字段名、类型与 Prisma 保持原样(IntStringBooleanDateTimeFloatJson等),因此你已有的 Prisma 建模经验可以平移过来。

一个现实项目里实体长什么样,可以参考仓库中示例应用 kitchen-sink 的数据模型 schema.prisma(注意:该示例属于采用新版schema.prisma文件定义方式的仓库,字段语法与 v0.13 内嵌 PSL 完全同构):

model Task { id Int @id @default(autoincrement()) description String isDone Boolean @default(false) user User @relation(fields: [userId], references: [id]) userId Int votes TaskVote[] visibility TaskVisibility @default(PRIVATE) }

可以看到,除单列字段外,模型中还出现了关联(@relation)、反向关系列表(TaskVote[])与枚举默认值(@default(PRIVATE))——这些全部是标准 PSL,定义方式与Task三字段示例一脉相承。

3. 从定义到建表:四步工作流

定义实体只是第一步,v0.13 文档给出的完整落地流程是:

  1. .wasp文件中创建/更新实体——即上节的entity声明。
  2. 运行wasp db migrate-dev。该命令负责把数据库与.wasp文件中的实体定义同步起来,实现方式是生成迁移脚本(migration scripts):它对比目标模型与当前库,产出描述差异的 SQL 迁移。
  3. 迁移脚本会自动落在migrations/目录,务必将该目录提交进版本控制——迁移历史是团队协作与部署的基础。
  4. 在实现 Operations 时,用 Wasp 的 JavaScript API 操作数据库——即 Query/Action,v0.13 文档将此留给了 operations 章节。

关于第 2、3 步有两条实践边界:

  • 数据库连接是前提wasp db migrate-dev需要可连的数据库,migrations/目录里每个迁移带时间戳前缀(如20231124161113_initial)与.sql文件,可参考 migrations 目录 与其中的 migration_lock.toml(锁定 Prisma 迁移引擎方言)。
  • 切换数据库系统后必须重新迁移。v0.13 支持 SQLite(默认)与 PostgreSQL,生产部署需 PostgreSQL;由于迁移脚本与方言绑定,切换系统后要删除旧migrations/并重新wasp db migrate-dev(参见同版本 Databases 文档 的 “Migrating from SQLite to PostgreSQL” 一节)。

4. 使用实体:Operations 优先,Prisma Client 兜底

4.1 在 Operations 中使用实体(推荐路径)

绝大多数时候,实体是在Operations(Query & Action)的上下文中被使用的——Query 读、Action 写,且带有权限(public/private)语义。v0.13 文档将细节放在了 operations/overview 与 crud。

这一路径背后的机制在编译器中可以直接看到:实体(含其主键字段)会被转换成 CRUD 元数据,进而生成crud/<entityLower>/getcrud/tasks/get-allcrud/tasks/create等标准路由。源码测试 CrudTest.hs 固化了这份元数据的确切形状:

[ "name" .= crudOperationsName, -- "tasks" "operations" .= object operations, "entitiesArray" .= ("['Task']" :: String), "idFieldName" .= ("id" :: String), "entityLower" .= ("task" :: String), "entityUpper" .= ("Task" :: String) ]

idFieldName来自实体的主键字段,entityLower/entityUpper即第 2 节提到的自动复数/单数表名规则的直接体现:你只需要声明entity Task,Operations 路由、参数命名都由编译器派生。

4.2 直接使用 Prisma Client(需要更多控制时)

当 Wasp 封装的能力不够(复杂查询、原生 SQL、特殊事务语义等),可以绕过 Operations,直接 import Prisma Client。官方建议仍是:优先走 Wasp 机制,仅在需要 Wasp 未提供的特性时才直接操作 Prisma Client

限制条件:Prisma Client 只能在 Wasp 的服务端代码中使用(Action、Job、server-only 模块等),客户端代码不可用。用法:

import { prisma } from 'wasp/server' prisma.task.create({ description: "Read the Entities doc", isDone: true // almost :) })

注意prisma.task——实体模型名Task在这里变为 Prisma Client 上的小驼峰代理task,与表名tasksentityLower: "task"的命名链完全一致(见 4.1 的元数据)。TypeScript 版本代码相同,类型由生成的 Prisma Client 提供。

5. 源码视角:Wasp 如何解析你的实体定义

结合仓库中 v0.13 编译器(Haskell,waspc包)的源码结构,可以看清entity声明从文本到数据库动作的完整链路:

(1)PSL 被当作一等语法解析。Wasp 自带一套 Prisma Schema Language 的 AST、解析器与代码生成器,模块布局见 wasp-cli 的 Psl 源码目录:

  • Psl/Ast/Model.hs定义了模型 AST:
data Model = Model Name Body data Field = Field { _name :: String, _type :: FieldType, _typeModifiers :: [FieldTypeModifier], _attrs :: [Attribute] }

对照第 2 节的示例:id Int @id @default(autoincrement())会被解析为Field {_name = "id", _type = Int, _attrs = [@id, @default(autoincrement())]}。内置字段类型由 FieldType 枚举覆盖:StringBooleanIntBigIntFloatDecimalDateTimeJsonBytes,另支持UserType(关联到其他模型)与Unsupported(兜底未知类型);FieldTypeModifier 则对应[](列表)与?(可选)修饰符。这意味着 v0.13 对实体内部的字段类型、属性做了完整结构化理解,而不是简单的字符串透传。

(2)Entity 是一等 AppSpec 构件。Entity.hs 将实体建模为“包裹 PSL 模型体的 newtype”,并提供getFieldsgetIdField等访问器:

newtype Entity = Entity { pslModelBody :: Psl.Model.Body }

(3)主键识别有明确的判定规则。Psl/Util.hs 中,findIdField的判定条件就是“字段带有@id属性”(源码注释原文:We define an ID field as a field that has the @id attribute),同时findIdBlockAttribute支持@@id复合主键块属性。这个识别结果正是 4.1 中 CRUD 元数据idFieldName字段的来源,也解释了为什么每个实体必须有一个可定位的主键——它是 Operations/CRUD 生成按主键读取、更新、删除逻辑的依据。

(4)一个版本演进注记。从源码结构看,Entity 的 JSON 反序列化已被有意废弃(Entity.hs 的FromJSON直接返回失败信息:“entities are now defined via prisma.schema file”)。也就是说,在 Wasp 后续版本中实体定义从.wasp内嵌 PSL 迁移到了独立的schema.prisma文件(当前主干的 examples 各示例 均已如此)。阅读 v0.13 文档时请以“entity {=psl ... psl=}”为准;升级后只需把同一份 PSL 内容移入schema.prismamodel块,字段与属性语法不变。

6. 小结

  • 定义entity Task {=psl ... psl=}= Wasp 外壳 + 原生 PSL;表名自动取复数(tasks),@id标记主键,@default给出列默认值。
  • 落库wasp db migrate-dev生成迁移脚本并写入migrations/(提交它);换数据库系统需删库重建迁移。
  • 使用:首选 Operations(Query/Action),底层由编译器从实体元数据(主键、单复数名)派生 CRUD 路由;需要细粒度控制时,在服务端import { prisma } from 'wasp/server'直接操作 Prisma Client。
  • 原理:Wasp 编译器对 PSL 做了完整 AST 级解析(Psl/Ast/Model.hs),并按@id/@@id规则识别主键(Psl/Util.hs),这是 Operations 与自动 CRUD 能够按实体生成的基础。

完成实体定义之后,下一步自然是学习如何用 Operations 高效地读写它们:继续阅读 v0.13 版 Operations 总览 与 CRUD 文档。

【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询