跳至内容

关联查询

Prisma Client 的一个关键特性是能够查询两个或多个模型之间的关系。关联查询包括

嵌套读取

嵌套读取允许您从数据库中的多个表中读取相关数据——例如用户及其帖子。您可以

  • 使用include在查询响应中包含相关记录,例如用户的帖子或个人资料。
  • 使用嵌套的select包含来自相关记录的特定字段。您也可以在include内部嵌套select

以下示例返回单个用户及其帖子

dart
final user = await prisma.user.findFirst(
  include: UserInclude(
    posts: PrismaUnion.$1(true),
  ),
);

包含特定关系的所有字段

以下示例返回帖子及其作者

dart
final user = await prisma.post.findFirst(
  include: PostInclude(
    author: PrismaUnion.$1(true),
  ),
);

包含深度嵌套的关系

您可以嵌套include选项来包含关系的关系。以下示例返回用户的帖子,以及每个帖子的类别

dart
final user = await prisma.user.findFirst(
  include: UserInclude(
    posts: PrismaUnion.$2(
      UserPostsArgs(
        include: PostInclude(
          categories: PrismaUnion.$1(true),
        ),
      ),
    ),
  ),
);

选择特定的关系字段

您可以使用嵌套的select来选择要返回的关系字段的子集。例如,以下查询返回用户的name和每个相关帖子的title

dart
final user = await prisma.user.findFirst(
  select: UserSelect(
    name: true,
    posts: PrismaUnion.$2(
      UserPostsArgs(
        select: PostSelect(title: true),
      ),
    ),
  ),
);

您还可以将select嵌套在include内——以下示例返回所有User字段和每个帖子的title字段

dart
final user = await prisma.user.findFirst(
  include: UserInclude(
    posts: PrismaUnion.$2(
      UserPostsArgs(
        select: PostSelect(title: true),
      ),
    ),
  ),
);

请注意,您**不能**在同一级别上使用selectinclude。这意味着,如果您选择include用户的帖子并select每个帖子的title,则无法仅选择用户的email

dart
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选项

dart
final user = await prisma.user.findFirst(
  select: UserSelect(
    name: true,
    posts: PrismaUnion.$2(
      UserPostsArgs(
        select: PostSelect(title: true),
      ),
    ),
  ),
);

关系计数

您可以includeselect关系计数以及字段——例如,返回用户,例如,用户的帖子计数

dart
final relationCount = await prisma.user.findMany(
  include: UserInclude(
    $count: PrismaUnion.$2(
      UserCountArgs(
        select: UserCountOutputTypeSelect(posts: true),
      ),
    ),
  ),
);

过滤关系列表

当您使用selectinclude返回相关数据的子集时,您可以在selectinclude内部**过滤和排序关系列表**。

例如,以下查询返回所有用户以及与每个用户关联的未发布帖子的标题列表

dart
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编写相同的查询,如下所示

dart
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记录

dart
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查询来创建相关记录。

每种技术都有其优缺点

特性crteatecreateMany描述
一次创建一个记录性能可能较差。
在一个查询中创建所有记录性能可能更好。
支持嵌套其他关系*例如,您可以在一个查询中创建一个用户、几个帖子和每个帖子的几个评论。 *您可以在一对一关系中手动设置外键——例如:{ authorId: 9}
支持跳过重复记录使用skipDuplicates查询选项。
支持多对多关系例如,您可以创建一个用户和多个帖子(一个用户有多个帖子)
支持多对多关系例如,您可以创建一个帖子和几个类别(一个帖子可以有多个类别,一个类别可以有多个帖子)

以下查询使用嵌套的create来创建

  • 一个用户
  • 该用户的两个帖子
  • 每个帖子的一个帖子类别

该示例使用嵌套的include包含所有帖子和帖子类别

dart
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包含所有帖子

dart
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),
  ),
);

**注意**:在突出显示的查询中**无法**嵌套额外的createcreateMany,这意味着您无法同时创建用户、帖子和帖子类别。

您无法在createMany查询中访问关系,这意味着您无法在一个嵌套写入中创建多个用户和多个帖子。以下操作是**不可能的**

dart
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) 连接到三个现有的帖子

dart
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)

dart
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的新用户(如果该用户尚不存在)

dart
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 或唯一标识符

dart
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)

dart
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一对多关系中的所有相关记录(一个用户有多个帖子),请将关系设置为空列表,如下所示

dart
await prisma.user.update(
  where: UserWhereUniqueInput(id: 10),
  data: PrismaUnion.$1(
    UserUpdateInput(
      posts: PostUpdateManyWithoutAuthorNestedInput(
        set: PrismaUnion.$2([]),
      ),
    ),
  ),
);

删除特定User的所有相关Post记录

dart
await prisma.user.update(
  where: UserWhereUniqueInput(id: 10),
  data: PrismaUnion.$1(
    UserUpdateInput(
      posts: PostUpdateManyWithoutAuthorNestedInput(
        deleteMany: PrismaUnion.$1(
          PostScalarWhereInput(),
        ),
      ),
    ),
  ),
);

通过删除所有未发布的帖子来更新用户

dart
await prisma.user.update(
  where: UserWhereUniqueInput(id: 10),
  data: PrismaUnion.$1(
    UserUpdateInput(
      posts: PostUpdateManyWithoutAuthorNestedInput(
        deleteMany: PrismaUnion.$1(
          PostScalarWhereInput(
            published: PrismaUnion.$2(false),
          ),
        ),
      ),
    ),
  ),
);

通过删除特定帖子来更新用户

dart
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更新特定用户的全部相关记录。以下查询取消发布特定用户的全部帖子

dart
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 提供了someeverynone选项,用于根据关系“-多对多”一侧的相关记录的属性过滤记录。例如,根据用户的帖子属性过滤用户。

例如

需求要使用的查询选项
"我想要每个至少有一个未发布的Post记录的User的列表"一些帖子未发布
"我想要每个没有未发布的Post记录的User的列表"所有帖子均未发布
“我想获取一个仅包含未发布帖子记录的所有用户的列表”所有帖子均未发布

例如,以下查询返回满足以下条件的用户

  • 没有浏览量超过 100 的帖子
  • 所有帖子的点赞数小于或等于 50
dart
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 客户端提供 $isisNot 选项,用于根据关系“-to-one”端相关记录的属性筛选记录。例如,根据作者的属性筛选帖子。

例如,以下查询返回满足以下条件的所有帖子

  • 作者姓名不是 Bob
  • 作者年龄超过 40 岁
dart
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 返回所有没有帖子的用户

dart
await prisma.user.findMany(
  where: UserWhereInput(
    posts: PostListRelationFilter(
      none: PostWhereInput(),
    ),
  ),
);

筛选不存在“-to-one”关系

以下查询返回所有没有作者关系的帖子

dart
await prisma.post.findMany(
  where: PostWhereInput(
    author: PrismaUnion.$2(
      PrismaUnion.$2(const PrismaNull()),
    ),
  ),
);

以下查询返回至少有一篇帖子的所有用户

dart
await prisma.user.findMany(
  where: UserWhereInput(
    posts: PostListRelationFilter(
      some: PostWhereInput(),
    ),
  ),
);

根据 BSD-3-Clause 许可证发布