You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MikroORM中@ManyToOne关联Ref序列化格式问题求助

问题

使用带有@ManyToOne关联Ref类型的实体序列化JSON时,city字段仅返回ID字符串(如"city": "bd612c71"),但预期返回包含id的对象格式(如{"city": {"id": "bd612c71"}})。

当前返回JSON示例

{"id": "80856ca0","createdAt": "2023-07-10T01:48:48.000Z","updatedAt": "2023-07-10T01:48:48.000Z","hospital": {"id": "d8f6f9ce","city": "bd612c71","country": {"id": "cfb0a1c6","createdAt": "2023-07-10T01:48:48.000Z","updatedAt": "2023-07-10T01:48:48.000Z"},"deletedAt": null}}

相关实体代码

Hospital实体

@Entity({tableName: 'hospital'})
export default class Hospital extends AggregateRoot<Hospital, 'id'> {
    @PrimaryKey({ autoincrement: false, unique: true, type: 'varchar', length: 8, nullable: false })
    id!: string
    @ManyToOne(() => City, { ref: true })
    city!: Ref<City>
    @ManyToOne(() => Country, { ref: true })
    country!: Ref<Country>
    // More properties here
}

City实体

@Entity({tableName: 'city'})
export default class City extends AggregateRoot<City, 'id'> {
    @PrimaryKey({ autoincrement: false, unique: true, type: 'varchar', length: 8, nullable: false })
    id!: string
    @Property({ unique: true, type: 'character', length: 100, nullable: false })
    name!: string
    @OneToMany(() => Hospital, hospital => hospital.city)
    hospitals = new Collection<Hospital>(this)
}

注:AggregateRoot为自定义类,继承自BaseEntity<T, PK>

解决方案

这不是Bug,是Ref类型序列化的默认行为——Ref本身仅存储关联实体的ID,序列化时会直接输出ID字符串。要实现预期的对象格式,可通过以下几种方式处理:

1. 自定义实体的toJSON方法

在Hospital类中重写toJSON方法,手动将city转换为包含id的对象:

@Entity({tableName: 'hospital'})
export default class Hospital extends AggregateRoot<Hospital, 'id'> {
    // ... 原有属性定义

    toJSON() {
        const json = super.toJSON();
        if (this.city) {
            json.city = { id: this.city.id };
        }
        return json;
    }
}

如果country也需要统一格式,可同理处理。

2. 使用DTO(数据传输对象)转换

创建专门的HospitalDTO类,在序列化前将实体转换为DTO格式:

class HospitalDTO {
    id: string;
    createdAt: Date;
    updatedAt: Date;
    city: { id: string };
    country: { id: string; createdAt: Date; updatedAt: Date };
    // 其他需要的字段

    static fromEntity(hospital: Hospital): HospitalDTO {
        return {
            id: hospital.id,
            createdAt: hospital.createdAt,
            updatedAt: hospital.updatedAt,
            city: { id: hospital.city.id },
            country: {
                id: hospital.country.id,
                createdAt: hospital.country.createdAt,
                updatedAt: hospital.country.updatedAt
            }
            // 映射其他字段
        };
    }
}

// 使用时
const hospital = await hospitalRepository.findOne(...);
const hospitalDTO = HospitalDTO.fromEntity(hospital);
const json = JSON.stringify(hospitalDTO);

3. 调整关联配置(需权衡场景)

若不想用Ref类型,可移除{ ref: true }配置,直接关联City实体,但这样会导致查询时默认加载关联实体(可通过lazy: true配置懒加载),会增加数据库查询开销,需根据业务场景权衡:

@ManyToOne(() => City) // 移除ref: true
city!: City;

此时序列化时会输出实体对象(仅加载的字段),但如果是懒加载且未主动加载,可能会出现序列化异常。


内容的提问来源于stack exchange,提问作者z0mbieKale

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 15:35:20