数据库实体的id字段是否应该设为可选?有哪些常用处理方案?
常见处理方案
以下是不同场景下的通用最佳实践:
1. 拆分两种实体类型(最推荐,类型安全最高)
明确区分「待插入DB的未持久化实体」和「DB查询返回的已持久化实体」,从类型层面隔离两种场景的约束:
// 插入时使用的类型,不需要携带id interface InsertPerson { name: string; age: number; } // DB查询返回的类型,id为必选字段 interface PersistedPerson extends InsertPerson { id: number; }
如果用TypeScript还可以用工具类型避免重复定义字段:
// 先定义全量的已持久化类型 interface PersistedPerson { id: number; name: string; age: number; } // 直接排除id得到插入类型,无需重复编写字段 type InsertPerson = Omit<PersistedPerson, 'id'>
2. 单模型加可选标记+类型守卫
如果不想维护两个类型,可以把id设为可选字段,配合类型守卫判断实体状态:
class Person { id?: number; name: string; age: number; // 判断当前实体是否已经持久化到DB isPersisted(): this is { id: number } & Omit<Person, 'id'> { return this.id !== undefined; } }
使用时只要调用过isPersisted()判断为真,后续类型系统会自动识别id为必选字段,不会报空值错误。
3. 直接使用ORM内置特性
主流ORM框架都原生支持这个场景的处理,无需自己手动定义:
- Prisma 会自动生成对应模型的
CreateInput类型,自动排除自增id、有默认值的字段 - TypeORM 用
@PrimaryGeneratedColumn装饰的id字段,新建实例时无需赋值,调用save方法后会自动回填id - Django ORM、MyBatis 等其他语言的ORM也都有对应逻辑,插入后自动把自增id写回实体实例
内容的提问来源于stack exchange,提问作者carcade
相关产品推荐
相关产品推荐

