如何将Prisma模型关联外键设为可选?及表单默认值报错解决
解决NextJS + Prisma中Product模型可选字段与useForm类型不兼容问题
1. 确认Prisma Schema修改及客户端生成
首先确保你的Prisma Schema修改正确,为sizeId、colorId及关联字段添加?标记:
model Product { id Int @id @default(autoincrement()) name String sizeId Int? colorId Int? size Size? @relation(fields: [sizeId], references: [id]) color Color? @relation(fields: [colorId], references: [id]) // 其他业务字段 } model Size { id Int @id @default(autoincrement()) name String products Product[] } model Color { id Int @id @default(autoincrement()) name String products Product[] }
修改完成后必须重新生成Prisma客户端,否则类型不会更新:
npx prisma generate
2. 适配useForm的defaultValues类型
根据表单是创建新商品还是编辑已有商品,分别处理:
场景1:创建新商品
直接在defaultValues中为sizeId、colorId设置undefined或null,匹配Prisma生成的可选类型:
import { useForm } from 'react-hook-form'; import type { Product } from '@prisma/client'; // 排除表单不需要的字段(如id、创建时间等) type ProductFormInput = Omit<Product, 'id' | 'createdAt' | 'updatedAt'>; export default function ProductForm() { const { register, handleSubmit } = useForm<ProductFormInput>({ defaultValues: { name: '', sizeId: undefined, colorId: undefined, // 其他字段默认值 }, }); const onSubmit = handleSubmit(async (data) => { await prisma.product.create({ data }); // 提交后的逻辑(如跳转) }); return ( <form onSubmit={onSubmit}> {/* 表单输入组件 */} <input {...register('name')} placeholder="商品名称" /> {/* 尺寸、颜色选择组件 */} </form> ); }
场景2:编辑已有商品
从数据库获取商品数据后,直接将其作为defaultValues传入,数据库返回的sizeId/colorId可能为null,天然匹配可选类型:
import { useForm } from 'react-hook-form'; import type { Product } from '@prisma/client'; import { useState, useEffect } from 'react'; import { useRouter } from 'next/router'; import { prisma } from '@/lib/prisma'; export default function EditProductForm() { const router = useRouter(); const productId = router.query.id as string; const [product, setProduct] = useState<Product | null>(null); useEffect(() => { if (productId) { const fetchProduct = async () => { const data = await prisma.product.findUnique({ where: { id: parseInt(productId) }, }); setProduct(data); }; fetchProduct(); } }, [productId]); const { register, handleSubmit } = useForm<Product>({ defaultValues: product, mode: 'onChange', }); const onSubmit = handleSubmit(async (data) => { await prisma.product.update({ where: { id: parseInt(productId) }, data, }); router.push('/products'); }); return ( <form onSubmit={onSubmit}> {/* 表单输入组件 */} </form> ); }
3. 其他类型兼容处理
如果手动定义表单类型,确保sizeId和colorId的类型为number | undefined | null,与Prisma生成的类型完全一致。若遇到临时类型冲突,可使用类型断言(尽量少用):
defaultValues: { name: '', sizeId: undefined as number | undefined, colorId: undefined as number | undefined, }
常见误区
- 未执行
npx prisma generate:修改Schema后必须重新生成客户端,否则类型还是旧的必填类型。 - 错误设置默认值:比如给
sizeId设为0,这会被视为有效Int值,与可选类型的预期不符,应使用undefined或null。
内容的提问来源于stack exchange,提问作者Jean Mako
相关产品推荐
相关产品推荐

