使用Prisma时@updatedAt字段调用.update()后未更新的问题
Prisma @updatedAt 字段在更新关联时未自动更新的解决方案
问题原因
Prisma的@updatedAt注解默认是客户端层面自动更新,仅当直接修改主表(如Channel)的字段时才会触发。你当前的操作是通过connect关联User到Channel,本质上修改的是中间关联表,主表本身的字段没有变化,所以Prisma不会自动更新updatedAt。
另外你提到的DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP是MySQL语法,PostgreSQL不支持这种写法,需要用触发器实现数据库层面的自动更新。
解决方案
方案1:手动显式更新updatedAt
在update操作的data里直接指定updatedAt为当前时间,这是最直接的解决方式:
await this.prismaService.channel.update({ where: { id: channelId, }, data: { users: { connect: { id: userId, }, }, updatedAt: new Date(), // 手动更新时间戳 }, include: channelIncludes, });
方案2:用Prisma中间件自动处理
如果不想每次关联操作都手动加updatedAt,可以编写Prisma中间件,监听update操作,当检测到关联修改时自动更新主表的updatedAt:
// src/prisma/middleware.ts import { PrismaClient } from '@prisma/client'; export function addUpdatedAtMiddleware(prisma: PrismaClient) { prisma.$use(async (params, next) => { // 仅处理update和updateMany操作 if (params.action === 'update' || params.action === 'updateMany') { // 判断data中是否包含关联操作(如connect/disconnect等) const hasRelationOp = Object.keys(params.data || {}).some(key => { const value = params.data[key]; return value && typeof value === 'object' && ( 'connect' in value || 'disconnect' in value || 'update' in value || 'connectOrCreate' in value || 'delete' in value || 'set' in value ); }); if (hasRelationOp) { params.data.updatedAt = new Date(); } } return next(params); }); }
然后在NestJS的Prisma服务中注册中间件:
// src/prisma/prisma.service.ts import { Injectable, OnModuleInit } from '@nestjs/common'; import { PrismaClient } from '@prisma/client'; import { addUpdatedAtMiddleware } from './middleware'; @Injectable() export class PrismaService extends PrismaClient implements OnModuleInit { async onModuleInit() { addUpdatedAtMiddleware(this); await this.$connect(); } }
方案3:数据库层面添加触发器(PostgreSQL)
如果希望从数据库层面强制保证updatedAt自动更新,不受客户端操作影响,可以给channels表添加触发器:
- 创建触发器函数:
CREATE OR REPLACE FUNCTION update_updated_at_column() RETURNS TRIGGER AS $$ BEGIN NEW."updatedAt" = CURRENT_TIMESTAMP; RETURN NEW; END; $$ LANGUAGE plpgsql;
- 绑定触发器到
channels表:
CREATE TRIGGER update_channels_updated_at BEFORE UPDATE ON "channels" FOR EACH ROW EXECUTE FUNCTION update_updated_at_column();
注意:同时使用Prisma客户端的
@updatedAt和数据库触发器可能导致时间重复更新,建议二选一。如果选择数据库层面实现,可以把模型中的@updatedAt改为@default(now()),避免Prisma客户端干预:updatedAt DateTime @default(now())
内容的提问来源于stack exchange,提问作者Abdel
相关产品推荐
相关产品推荐

