You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Prisma中同一查询无法更新关联表问题求助

问题:更新Payment状态时无法同时更新关联Wallet余额

我在使用Prisma时,尝试将Payment的状态更新为PAID的同时,在同一个查询里更新关联的Wallet余额,但执行时报错。

Prisma Schema

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}

model User {
  uid         String    @id @default(cuid())
  created_at  DateTime
  username    String
  roles       String[]
  accessToken String
  session     Session[]
  walletId    String    @unique
  wallet      Wallet    @relation(fields: [walletId], references: [id])
  payment     Payment[]
}

model Session {
  id       String   @id @default(uuid())
  userid   String
  expires  DateTime @db.Timestamptz
  cookieId String   @unique
  user     User     @relation(fields: [userid], references: [uid])
}

model Wallet {
  id      String    @id @default(uuid())
  balance Int       @default(0)
  user    User?
  payment  Payment[]
}

model Order {
  id        String   @id @default(uuid())
  createdAt DateTime @default(now())
  product   Product  @relation(fields: [productId], references: [id]) //Note that only one product can be ordered at a time
  payment   Payment  @relation(fields: [paymentId], references: [piPaymentId])
  productId String
  paymentId String   @unique
}

model Payment {
  piPaymentId String        @id @unique
  amount      Float
  txid        String        @default("")
  status      PaymentStatus @default(PENDING)
  user        User          @relation(fields: [userId], references: [uid])
  order       Order?
  wallet      Wallet        @relation(fields: [walletId], references: [id])
  walletId    String
  userId      String
}

model Product {
  id     String  @id @default(uuid())
  name   String
  price  Float
  amount Int //Note at this moment we only support coins as a product
  order  Order[]
}

enum PaymentStatus {
  PENDING
  PAID
  FAILED
  CANCELLED
}

正常的Payment创建代码

async create(payment: APIRequests.Paymnet.Create) {
  return await this.db.prisma.payment.create({
    data: {
      piPaymentId: payment.paymentId,
      user: {
        connect: {
          uid: payment.userId,
        },
      },
      amount: payment.amount,
      status: "PENDING",
      wallet: {
        connect: {
          id: payment.walletId
        }
      }
    }
  });
}

出错的更新代码

async complete(payment: APIRequests.Paymnet.Complete) {
  await this.db.prisma.payment.update({
    where: {
      piPaymentId: payment.paymentId
    },
    data: {
      status: "PAID",
      txid: payment.txid,
      wallet: {
        update: {
          balance: {
            decrement: payment.amount
          }
        }
      }
    }
  });
}

报错信息

Error: 
Invalid `prisma.payment.update()` invocation:

{
  where: {
    piPaymentId: 'some paymentID'
  },
  data: {
    status: 'PAID',
    txid: 'some txid',
    wallet: {
    ~~~~~~
      update: {
        balance: {
          decrement: 0.1
        }
      }
    }
  }
}

Unknown arg `wallet` in data.wallet for type PaymentUncheckedUpdateInput. Did you mean `walletId`? Available args:   
type PaymentUncheckedUpdateInput {
  piPaymentId?: String | StringFieldUpdateOperationsInput
  amount?: Float | FloatFieldUpdateOperationsInput
  txid?: String | StringFieldUpdateOperationsInput
  status?: PaymentStatus | EnumPaymentStatusFieldUpdateOperationsInput
  order?: OrderUncheckedUpdateOneWithoutPaymentNestedInput
  walletId?: String | StringFieldUpdateOperationsInput
  userId?: String | StringFieldUpdateOperationsInput
}

解决方案

核心原因

Prisma的update操作仅支持更新当前模型的字段(含外键字段如walletId),不允许直接通过关联关系字段(如wallet)嵌套更新关联模型。而create操作支持connect/create关联模型,这是两种操作的差异点。

方法1:使用事务(推荐)

通过Prisma事务保证两个操作的原子性,避免部分成功的情况:

async complete(payment: APIRequests.Paymnet.Complete) {
  // 先获取目标Payment关联的walletId
  const paymentRecord = await this.db.prisma.payment.findUnique({
    where: { piPaymentId: payment.paymentId },
    select: { walletId: true }
  });

  if (!paymentRecord) {
    throw new Error("Payment记录不存在");
  }

  // 执行事务:更新Payment状态 + 更新Wallet余额
  await this.db.prisma.$transaction([
    this.db.prisma.payment.update({
      where: { piPaymentId: payment.paymentId },
      data: { status: "PAID", txid: payment.txid }
    }),
    this.db.prisma.wallet.update({
      where: { id: paymentRecord.walletId },
      data: { balance: { decrement: payment.amount } }
    })
  ]);
}

方法2:从Wallet端反向更新

如果业务允许,也可以从Wallet模型的update操作中,嵌套更新关联的Payment:

async complete(payment: APIRequests.Paymnet.Complete) {
  await this.db.prisma.wallet.update({
    where: {
      // 通过关联的Payment筛选目标Wallet
      payment: { some: { piPaymentId: payment.paymentId } }
    },
    data: {
      balance: { decrement: payment.amount },
      // 嵌套更新关联的Payment状态
      payment: {
        update: {
          where: { piPaymentId: payment.paymentId },
          data: { status: "PAID", txid: payment.txid }
        }
      }
    }
  });
}

内容的提问来源于stack exchange,提问作者LeVarez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 01:21:06