如何保存使用自定义类ID的多对多关系
自定义ID类在多对多关联保存时无法正确序列化问题
问题背景
使用自定义UserId和OrganizationId类生成带前缀的字符串ID(如USER-1234、Org-1234),为User和Organization实体建立多对多关联。手动插入数据后可正常查询关联关系,但执行保存操作时,连接表插入语句使用DEFAULT值,触发"Field 'organizationId' doesn't have a default value"错误。
相关代码
实体类定义
@Entity('user') export class User { @PrimaryColumn({ type: 'varchar', transformer: idTransformer, }) @Property() id: UserId; // 其他字段... @ManyToMany(() => Organization, (org) => org.users) @Default([]) @JoinTable({ name: 'user_organization' }) organizations: Array<Organization>; } @Entity('organization') export class Organization { @PrimaryColumn({ type: 'varchar', transformer: idTransformer, }) @Property() id: OrganizationId; // 其他字段... @ManyToMany(() => User, (user) => user.organizations) @JoinTable({ name: 'user_organization' }) @Default([]) users: Array<User>; }
ID转换器实现
export const idTransformer = { to: (value: Id) => { return value.getValue(); }, from: <T extends Id>(value: string): T => { if (value) { return IdUtils.fromHex(value); } return null; }, };
触发错误的保存操作
const org = await orgRepository.getOrg(); const user = await getUser(); org.users.add(user); await orgRepository.save(org);
错误信息
{ "name": "QueryFailedError", "message": "Field 'organizationId' doesn't have a default value", "status": 500, "errors": [], "stack": "QueryFailedError: Field 'organizationId' doesn't have a default value\n..." }
MySQL执行日志
INSERT INTO `user_organization`(`organizationId`, `userId`) VALUES (DEFAULT, DEFAULT)
解决方案
1. 为自定义ID类添加toString方法
ORM在处理关联关系时,可能直接调用对象的toString()方法而非字段转换器。给Id基类添加该方法,确保能输出正确的ID字符串:
class Id { private value: string; constructor(value: string) { this.value = value; } getValue(): string { return this.value; } toString(): string { return this.getValue(); } }
2. 显式配置连接表字段的转换器
部分ORM(如TypeORM)不会自动将实体主键的转换器应用到连接表,需在@JoinTable中手动指定:
// 修改User类中的多对多关联配置 @ManyToMany(() => Organization, (org) => org.users) @JoinTable({ name: 'user_organization', joinColumns: [ { name: 'userId', referencedColumnName: 'id', transformer: idTransformer, }, ], inverseJoinColumns: [ { name: 'organizationId', referencedColumnName: 'id', transformer: idTransformer, }, ], }) organizations: Array<Organization>;
同时移除Organization类中的@JoinTable注解,多对多关联只需一方配置即可。
3. 检查ORM版本与配置
确认使用的ORM版本是否存在自定义ID转换器的兼容问题,升级到最新稳定版。同时验证实体元数据是否正确加载,转换器是否被ORM识别。
4. 手动插入连接表数据
若以上方法无效,可绕过ORM自动关联逻辑,直接执行SQL插入:
await connection.query( 'INSERT INTO user_organization (userId, organizationId) VALUES (?, ?)', [user.id.getValue(), org.id.getValue()] );
内容的提问来源于stack exchange,提问作者Kousha
相关产品推荐
相关产品推荐

