Server组件动态路由中async-await调用Prisma报错的修复咨询
点击「Add New」按钮时触发以下错误:
PrismaClientKnownRequestError: Invalid
prisma.billboard.findUnique()invocation:
Inconsistent column data: Malformed ObjectID: provided hex string representation must be exactly 12 bytes, instead got: "new", length 3.
at async BillboardPage (billboards/[billboardId]/page.tsx:14:23)
digest: "1047868513"
报错页面代码(billboards/[billboardId]/page.tsx)
const BillboardPage = async ({ params }: { params: { billboardId: string } }) => { console.log("Billboard ID:", params.billboardId); const billboard = await prismadb.billboard.findUnique({ where: { id: params.billboardId } }); return ( <div className="flex-col"> <div className="flex-1 space-y-4 p-8 pt-6"> <BillboardForm initialData={billboard} /> </div> </div> ); }; export default BillboardPage;
路由触发代码
export const BillboardClient = () => { const router = useRouter(); const params = useParams(); return ( <> <div className="flex items-center justify-between"> <Heading title="Billboards (0)" description="Manage Billboards for your store" /> <Button onClick={() => router.push(`/${params.storeId}/billboards/new`)}> <Plus className="mr-w h-4 w-4"/> Add New </Button> </div> <Separator /> </> ) }
动态路由billboards/[billboardId]会匹配所有billboards/xxx格式的路径,包括跳转的billboards/new。这导致BillboardPage组件把字符串"new"当作billboardId传入Prisma查询,但Prisma要求id字段必须是12字节的ObjectID格式,直接用"new"查询触发了格式错误。
方案1:拆分路由,新增单独的新建页面
在billboards目录下创建new/page.tsx,专门处理新建逻辑:
// billboards/new/page.tsx const NewBillboardPage = () => { return ( <div className="flex-col"> <div className="flex-1 space-y-4 p-8 pt-6"> <BillboardForm initialData={null} /> {/* 传null表示新建模式 */} </div> </div> ); }; export default NewBillboardPage;
同时修改原BillboardPage,增加ID格式校验:
// billboards/[billboardId]/page.tsx const BillboardPage = async ({ params }: { params: { billboardId: string } }) => { // 校验ObjectID格式(24位十六进制字符串) if (!/^[0-9a-fA-F]{24}$/.test(params.billboardId)) { return <div>无效的广告牌ID</div>; } const billboard = await prismadb.billboard.findUnique({ where: { id: params.billboardId } }); if (!billboard) { return <div>未找到该广告牌</div>; } return ( <div className="flex-col"> <div className="flex-1 space-y-4 p-8 pt-6"> <BillboardForm initialData={billboard} /> </div> </div> ); }; export default BillboardPage;
方案2:在现有页面中区分编辑/新建模式
如果不想新增页面,可以在BillboardPage中判断参数是否为"new",切换逻辑:
const BillboardPage = async ({ params }: { params: { billboardId: string } }) => { let billboard = null; const isNew = params.billboardId === "new"; if (!isNew) { // 非新建模式,校验ID格式并查询数据 if (!/^[0-9a-fA-F]{24}$/.test(params.billboardId)) { return <div>无效的广告牌ID</div>; } billboard = await prismadb.billboard.findUnique({ where: { id: params.billboardId } }); if (!billboard) { return <div>未找到该广告牌</div>; } } return ( <div className="flex-col"> <div className="flex-1 space-y-4 p-8 pt-6"> <BillboardForm initialData={billboard} isNew={isNew} /> {/* 传递新建状态给表单 */} </div> </div> ); }; export default BillboardPage;
注意需要同步修改BillboardForm组件,使其能处理initialData为null的情况,区分新增和编辑逻辑。
内容的提问来源于stack exchange,提问作者Anis Riaz

