关联查询
Prisma Client 的一个关键特性是能够查询两个或多个模型之间的关系。关联查询包括
嵌套读取
嵌套读取允许您从数据库中的多个表中读取相关数据——例如用户及其帖子。您可以
- 使用
include
在查询响应中包含相关记录,例如用户的帖子或个人资料。 - 使用嵌套的
select
包含来自相关记录的特定字段。您也可以在include
内部嵌套select
。
以下示例返回单个用户及其帖子
final user = await prisma.user.findFirst(
include: UserInclude(
posts: PrismaUnion.$1(true),
),
);
包含特定关系的所有字段
以下示例返回帖子及其作者
final user = await prisma.post.findFirst(
include: PostInclude(
author: PrismaUnion.$1(true),
),
);
包含深度嵌套的关系
您可以嵌套include
选项来包含关系的关系。以下示例返回用户的帖子,以及每个帖子的类别
final user = await prisma.user.findFirst(
include: UserInclude(
posts: PrismaUnion.$2(
UserPostsArgs(
include: PostInclude(
categories: PrismaUnion.$1(true),
),
),
),
),
);
选择特定的关系字段
您可以使用嵌套的select
来选择要返回的关系字段的子集。例如,以下查询返回用户的name
和每个相关帖子的title
final user = await prisma.user.findFirst(
select: UserSelect(
name: true,
posts: PrismaUnion.$2(
UserPostsArgs(
select: PostSelect(title: true),
),
),
),
);
您还可以将select
嵌套在include
内——以下示例返回所有User字段和每个帖子的title
字段
final user = await prisma.user.findFirst(
include: UserInclude(
posts: PrismaUnion.$2(
UserPostsArgs(
select: PostSelect(title: true),
),
),
),
);
请注意,您**不能**在同一级别上使用select
和include
。这意味着,如果您选择include
用户的帖子并select
每个帖子的title
,则无法仅选择用户的email
final user = await prisma.user.findFirst(
select: UserSelect( // This won't work!
email: true,
),
include: UserInclude( // This won't work!
posts: PrismaUnion.$2(
UserPostsArgs(
select: PostSelect(title: true),
),
),
),
);
而是使用嵌套的select选项
final user = await prisma.user.findFirst(
select: UserSelect(
name: true,
posts: PrismaUnion.$2(
UserPostsArgs(
select: PostSelect(title: true),
),
),
),
);
关系计数
您可以include
或select
关系计数以及字段——例如,返回用户,例如,用户的帖子计数
final relationCount = await prisma.user.findMany(
include: UserInclude(
$count: PrismaUnion.$2(
UserCountArgs(
select: UserCountOutputTypeSelect(posts: true),
),
),
),
);
过滤关系列表
当您使用select
或include
返回相关数据的子集时,您可以在select
或include
内部**过滤和排序关系列表**。
例如,以下查询返回所有用户以及与每个用户关联的未发布帖子的标题列表
final filterListOfRelations = await prisma.user.findFirst(
select: UserSelect(
posts: PrismaUnion.$2(
UserPostsArgs(
where: PostWhereInput(
published: PrismaUnion.$2(false),
),
orderBy: PrismaUnion.$2(
PostOrderByWithRelationInput(
title: SortOrder.asc,
),
),
select: PostSelect(title: true),
),
),
),
);
您也可以使用include
编写相同的查询,如下所示
final filterListOfRelationsInclude = await prisma.user.findFirst(
include: UserInclude(
posts: PrismaUnion.$2(
UserPostsArgs(
where: PostWhereInput(
published: PrismaUnion.$2(false),
),
orderBy: PrismaUnion.$2(
PostOrderByWithRelationInput(
title: SortOrder.asc,
),
),
),
),
),
);
嵌套写入
嵌套写入允许您在**单个事务**中将**关系数据**写入您的数据库。
嵌套写入
- 为在单个Prisma Client查询中跨多个表创建、更新或删除数据提供**事务保证**。如果查询的任何部分失败(例如,创建用户成功但创建帖子失败),Prisma Client将回滚所有更改。
- 支持数据模型支持的任何级别的嵌套。
- 在使用模型的创建或更新查询时,可用于关系字段。以下部分显示了每个查询可用的嵌套写入选项。
创建相关记录
您可以同时创建一个记录和一个或多个相关记录。以下查询创建一个User记录和两个相关的Post记录
final createRelatedRecord = await prisma.user.create(
data: PrismaUnion.$1(
UserCreateInput(
email: "elsa@examole.com",
name: PrismaUnion.$1("Elsa"),
posts: PostCreateNestedManyWithoutAuthorInput(
create: PrismaUnion.$2(
PrismaUnion.$1([
PostCreateWithoutAuthorInput(
title: "Join the Resistance",
),
PostCreateWithoutAuthorInput(
title: "Join the Resistance 2",
),
]),
),
),
),
),
include: UserInclude(
posts: PrismaUnion.$1(true),
),
);
创建单个记录和多个相关记录
有两种方法可以创建或更新单个记录和多个相关记录——例如,具有多个帖子的用户
- 使用嵌套的
create
查询来创建相关记录。 - 使用嵌套的
createMany
查询来创建相关记录。
每种技术都有其优缺点
特性 | crteate | createMany | 描述 |
---|---|---|---|
一次创建一个记录 | ✅ | ❌ | 性能可能较差。 |
在一个查询中创建所有记录 | ❌ | ✅ | 性能可能更好。 |
支持嵌套其他关系 | ✅ | ❌ * | 例如,您可以在一个查询中创建一个用户、几个帖子和每个帖子的几个评论。 * 您可以在一对一关系中手动设置外键——例如:{ authorId: 9} |
支持跳过重复记录 | ❌ | ❌ | 使用skipDuplicates 查询选项。 |
支持多对多关系 | ✅ | ✅ | 例如,您可以创建一个用户和多个帖子(一个用户有多个帖子) |
支持多对多关系 | ✅ | ❌ | 例如,您可以创建一个帖子和几个类别(一个帖子可以有多个类别,一个类别可以有多个帖子) |
以下查询使用嵌套的create
来创建
- 一个用户
- 该用户的两个帖子
- 每个帖子的一个帖子类别
该示例使用嵌套的include
包含所有帖子和帖子类别
await prisma.user.create(
data: PrismaUnion.$1(
UserCreateInput(
email: "vv@prisma.pub",
name: PrismaUnion.$1("Vivian"),
posts: PostCreateNestedManyWithoutAuthorInput(
create: PrismaUnion.$2(
PrismaUnion.$1([
PostCreateWithoutAuthorInput(
title: "Join the Resistance",
categories: CategoryCreateNestedManyWithoutPostsInput(
create: PrismaUnion.$1(
CategoryCreateWithoutPostsInput(name: "Easy cooking"),
),
),
),
PostCreateWithoutAuthorInput(
title: "Join the Resistance 2",
),
]),
),
),
),
),
include: UserInclude(
posts: PrismaUnion.$2(
UserPostsArgs(
include: PostInclude(
categories: PrismaUnion.$1(true),
),
),
),
),
);
以下查询使用嵌套的createMany
来创建
- 一个用户
- 该用户的两个帖子
该示例使用嵌套的include
包含所有帖子
await prisma.user.create(
data: PrismaUnion.$1(
UserCreateInput(
email: "saanvi@examole.com",
posts: PostCreateNestedManyWithoutAuthorInput(
createMany: PostCreateManyAuthorInputEnvelope(
data: PrismaUnion.$2([
PostCreateManyAuthorInput(title: "My first post"),
PostCreateManyAuthorInput(title: "My second post"),
]),
),
),
),
),
include: UserInclude(
posts: PrismaUnion.$1(true),
),
);
**注意**:在突出显示的查询中**无法**嵌套额外的
create
或createMany
,这意味着您无法同时创建用户、帖子和帖子类别。
创建多个记录和多个相关记录
您无法在createMany
查询中访问关系,这意味着您无法在一个嵌套写入中创建多个用户和多个帖子。以下操作是**不可能的**
await prisma.user.createMany(
data: PrismaUnion.$2([
UserCreateManyInput(
email: "yewande@a.com",
name: PrismaUnion.$1("Yewande"),
// posts: ... // Not possible to create posts! Type-safe, not `posts` field on `UserCreateManyInput`
),
UserCreateManyInput(
email: "noor@a.com",
name: PrismaUnion.$1("Noor"),
// posts: ... // Not possible to create posts! Type-safe, not `posts` field on `UserCreateManyInput`
),
]),
);
连接多个记录
以下查询创建 (create
) 一个新的User
记录并将该记录 (connect
) 连接到三个现有的帖子
await prisma.user.create(
data: PrismaUnion.$1(
UserCreateInput(
email: 'vlad@prisma.pub',
posts: PostCreateNestedManyWithoutAuthorInput(
connect: PrismaUnion.$2([
PostWhereUniqueInput(id: 1),
PostWhereUniqueInput(id: 2),
PostWhereUniqueInput(id: 3),
// ... More `PostWhereUniqueInput` objects
]),
),
),
),
include: UserInclude(
posts: PrismaUnion.$1(true),
),
);
信息
如果任何帖子记录都找不到,Prisma Client 会抛出异常
connect: [{ id: 1 }, { id: 2 }, { id: 3 }]
连接单个记录
您可以将现有记录connect
到新用户或现有用户。以下查询将现有帖子 (id: 11
) 连接到现有用户 (id: 9
)
await prisma.user.update(
where: UserWhereUniqueInput(id: 9),
data: PrismaUnion.$1(
UserUpdateInput(
posts: PostUpdateManyWithoutAuthorNestedInput(
connect: PrismaUnion.$1(
PostWhereUniqueInput(id: 11),
),
),
),
),
include: UserInclude(
posts: PrismaUnion.$1(true),
),
);
连接或创建记录
如果相关记录可能已经存在也可能不存在,请使用connectOrCreate
连接相关记录
连接电子邮件地址为viola@prisma.io的用户或创建电子邮件地址为viola@prisma.io的新用户(如果该用户尚不存在)
await prisma.post.create(
data: PrismaUnion.$1(
PostCreateInput(
title: "My first post",
author: UserCreateNestedOneWithoutPostsInput(
connectOrCreate: UserCreateOrConnectWithoutPostsInput(
where: UserWhereUniqueInput(email: "viola@prisma.io"),
create: PrismaUnion.$1(
UserCreateWithoutPostsInput(
email: "viola@prisma.io",
name: PrismaUnion.$1("Viola"),
),
),
),
),
),
),
include: PostInclude(
author: PrismaUnion.$1(true),
),
);
断开相关记录
要从记录列表中disconnect
一个(例如,特定博客文章),请提供要断开的记录的 ID 或唯一标识符
await prisma.user.update(
where: UserWhereUniqueInput(id: 10),
data: PrismaUnion.$1(
UserUpdateInput(
posts: PostUpdateManyWithoutAuthorNestedInput(
disconnect: PrismaUnion.$2([
PostWhereUniqueInput(id: 11),
PostWhereUniqueInput(id: 12),
]),
),
),
),
include: UserInclude(
posts: PrismaUnion.$1(true),
),
);
要disconnect
一个记录(例如,帖子的作者),请使用disconnect: PrismaUnion.$1(true)
await prisma.post.update(
where: PostWhereUniqueInput(id: 11),
data: PrismaUnion.$1(
PostUpdateInput(
author: UserUpdateOneWithoutPostsNestedInput(
disconnect: PrismaUnion.$1(true),
),
),
),
include: PostInclude(
author: PrismaUnion.$1(true),
),
);
断开所有相关记录
要disconnect
一对多关系中的所有相关记录(一个用户有多个帖子),请将关系设置为空列表,如下所示
await prisma.user.update(
where: UserWhereUniqueInput(id: 10),
data: PrismaUnion.$1(
UserUpdateInput(
posts: PostUpdateManyWithoutAuthorNestedInput(
set: PrismaUnion.$2([]),
),
),
),
);
删除所有相关记录
删除特定User
的所有相关Post
记录
await prisma.user.update(
where: UserWhereUniqueInput(id: 10),
data: PrismaUnion.$1(
UserUpdateInput(
posts: PostUpdateManyWithoutAuthorNestedInput(
deleteMany: PrismaUnion.$1(
PostScalarWhereInput(),
),
),
),
),
);
删除特定相关记录
通过删除所有未发布的帖子来更新用户
await prisma.user.update(
where: UserWhereUniqueInput(id: 10),
data: PrismaUnion.$1(
UserUpdateInput(
posts: PostUpdateManyWithoutAuthorNestedInput(
deleteMany: PrismaUnion.$1(
PostScalarWhereInput(
published: PrismaUnion.$2(false),
),
),
),
),
),
);
通过删除特定帖子来更新用户
await prisma.user.update(
where: UserWhereUniqueInput(id: 10),
data: PrismaUnion.$1(
UserUpdateInput(
posts: PostUpdateManyWithoutAuthorNestedInput(
deleteMany: PrismaUnion.$2([
PostScalarWhereInput(id: PrismaUnion.$2(11)),
PostScalarWhereInput(id: PrismaUnion.$2(7)),
]),
),
),
),
);
更新所有相关记录(或过滤)
您可以使用嵌套的updateMany
更新特定用户的全部相关记录。以下查询取消发布特定用户的全部帖子
await prisma.user.update(
where: UserWhereUniqueInput(id: 10),
data: PrismaUnion.$1(
UserUpdateInput(
posts: PostUpdateManyWithoutAuthorNestedInput(
updateMany: PrismaUnion.$1(
PostUpdateManyWithWhereWithoutAuthorInput(
where: PostScalarWhereInput(
published: PrismaUnion.$2(true),
),
data: PrismaUnion.$1(
PostUpdateManyMutationInput(
published: PrismaUnion.$1(false),
),
),
),
),
),
),
),
);
关系过滤器
过滤“-多对多”关系
Prisma Client 提供了some
、every
和none
选项,用于根据关系“-多对多”一侧的相关记录的属性过滤记录。例如,根据用户的帖子属性过滤用户。
例如
需求 | 要使用的查询选项 |
---|---|
"我想要每个至少有一个未发布的Post记录的User的列表" | 一些帖子未发布 |
"我想要每个没有未发布的Post记录的User的列表" | 所有帖子均未发布 |
“我想获取一个仅包含未发布帖子记录的所有用户的列表” | 所有帖子均未发布 |
例如,以下查询返回满足以下条件的用户
- 没有浏览量超过 100 的帖子
- 所有帖子的点赞数小于或等于 50
await prisma.user.findMany(
where: UserWhereInput(
posts: PostListRelationFilter(
none: PostWhereInput(
views: PrismaUnion.$1(
IntFilter(gt: PrismaUnion.$1(100)),
),
),
every: PostWhereInput(
likes: PrismaUnion.$1(
IntFilter(lte: PrismaUnion.$1(50)),
),
),
),
),
);
筛选“-to-one”关系
Prisma Dart 客户端提供 $is
和 isNot
选项,用于根据关系“-to-one”端相关记录的属性筛选记录。例如,根据作者的属性筛选帖子。
例如,以下查询返回满足以下条件的所有帖子
- 作者姓名不是 Bob
- 作者年龄超过 40 岁
await prisma.post.findMany(
where: PostWhereInput(
author: PrismaUnion.$1(
UserNullableRelationFilter(
isNot: PrismaUnion.$1(
UserWhereInput(
name: PrismaUnion.$2(
PrismaUnion.$1("Bob"),
),
),
),
$is: PrismaUnion.$1(
UserWhereInput(
age: PrismaUnion.$1(
IntNullableFilter(
gt: PrismaUnion.$1(40),
),
),
),
),
),
),
),
);
筛选不存在“-to-many”记录
例如,以下查询使用 none
返回所有没有帖子的用户
await prisma.user.findMany(
where: UserWhereInput(
posts: PostListRelationFilter(
none: PostWhereInput(),
),
),
);
筛选不存在“-to-one”关系
以下查询返回所有没有作者关系的帖子
await prisma.post.findMany(
where: PostWhereInput(
author: PrismaUnion.$2(
PrismaUnion.$2(const PrismaNull()),
),
),
);
筛选存在相关记录
以下查询返回至少有一篇帖子的所有用户
await prisma.user.findMany(
where: UserWhereInput(
posts: PostListRelationFilter(
some: PostWhereInput(),
),
),
);