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

如何自动更新并基于关联获取PhotoComment中的用户评分字段?

问题描述

我尝试关联Photo、PhotoComment和PhotoRating三个实体,需求如下:

  • 用户可对照片评分,单个用户对单张照片仅能评一次
  • 照片可拥有多条用户评论及多个用户评分
  • 在该照片的所有评论中显示当前用户的评分
  • 调用ratePhoto方法修改评分时,自动更新评论中的评分

目前遇到的问题:调用ratePhoto方法后,PGAdmin中可见PhotoComment未关联photoRatingId,评论中的评分也未更新,但ratePhoto能正确保存照片的评分。技术栈为NestJS、TypeORM、PostgreSQL、RxJS,优先使用Repository而非QueryBuilder。相关代码如下:

photos.service.ts

public ratePhoto(photoId: number, ratePhotoDto: RatePhotoDto, user: User): Observable<any> {
        return this.getPhoto(photoId).pipe(
            switchMap((photo: Photo) => from(this.photoRatingRepository.findOneBy({ photo: { id: photo.id }, user: { id: user.id } })).pipe(
                map((photoRating: PhotoRating) => {
                    if (!photoRating) {
                        const newRating: PhotoRating = new PhotoRating();

                        newRating.rate = ratePhotoDto.rate;
                        newRating.user = user;
                        newRating.photo = photo;

                        return this.photoRatingRepository.save(newRating);
                    }

                    photoRating.rate = ratePhotoDto.rate;

                    return this.photoRatingRepository.save(photoRating);
                }),
            )),
        );
    }

photo.entity.ts

@Entity()
export class Photo {
    //...

    @OneToMany(() => PhotoComment, (photoComment: PhotoComment) => photoComment.photo)
    public photoComments: PhotoComment[];

    @OneToMany(() => PhotoRating, (photoRating: PhotoRating) => photoRating.photo)
    public photoRatings: PhotoRating[];
}

photo-comment.entity.ts

@Entity()
export class PhotoComment {
    //...

    @ManyToOne(() => Photo, (photo: Photo) => photo.photoComments, { onDelete: 'CASCADE' })
    public photo: Photo;

    @ManyToOne(() => PhotoRating, (photoRating: PhotoRating) => photoRating.photoComment)
    @JoinColumn({ name: 'rate' })
    public photoRating: PhotoRating;
}

photo-rating.entity.ts

@Entity()
@Unique(['user', 'photo'])
export class PhotoRating {
    //...
    
    @Transform(({ value }) => +value)
    @Column({ type: 'decimal', precision: 3, scale: 2, default: 0 })
    public rate: number;

    @ManyToOne(() => Photo, (photo: Photo) => photo.photoRatings, { onDelete: 'CASCADE' })
    public photo: Photo;

    @OneToMany(() => PhotoComment, (photoComment: PhotoComment) => photoComment.photoRating, { cascade: true })
    public photoComment: PhotoComment;
}
错误分析与解决方案

1. 实体关联逻辑错误

  • 外键列设置错误:PhotoComment中@JoinColumn({ name: 'rate' })把外键列指定为rate,但rate是PhotoRating的业务字段,而非主键。外键应关联PhotoRating的主键,正确列名应为photo_rating_id。
  • 关联字段命名错误:PhotoRating中的photoComment字段是@OneToMany关联,对应多个评论,应命名为复数photoComments。
  • 缺少用户关联:PhotoComment未关联User,无法定位当前用户对该照片的所有评论,导致无法批量更新关联关系。

2. 未维护评论与评分的关联关系

当前ratePhoto方法仅处理了PhotoRating的保存,未同步更新对应PhotoComment的photoRating关联,这是评论未关联评分的核心原因。

修正后的代码

photo-comment.entity.ts

@Entity()
export class PhotoComment {
    //...

    @ManyToOne(() => Photo, (photo: Photo) => photo.photoComments, { onDelete: 'CASCADE' })
    public photo: Photo;

    // 新增:每个评论归属一个用户
    @ManyToOne(() => User, { onDelete: 'CASCADE' })
    public user: User;

    @ManyToOne(() => PhotoRating, (photoRating: PhotoRating) => photoRating.photoComments)
    // 修正外键列名,关联PhotoRating的主键
    @JoinColumn({ name: 'photo_rating_id' })
    public photoRating: PhotoRating;
}

photo-rating.entity.ts

@Entity()
@Unique(['user', 'photo'])
export class PhotoRating {
    //...
    
    @Transform(({ value }) => +value)
    @Column({ type: 'decimal', precision: 3, scale: 2, default: 0 })
    public rate: number;

    @ManyToOne(() => Photo, (photo: Photo) => photo.photoRatings, { onDelete: 'CASCADE' })
    public photo: Photo;

    // 新增:每个评分归属一个用户
    @ManyToOne(() => User, { onDelete: 'CASCADE' })
    public user: User;

    // 修正字段名为复数,对应多条评论
    @OneToMany(() => PhotoComment, (photoComment: PhotoComment) => photoComment.photoRating, { cascade: true })
    public photoComments: PhotoComment[];
}

photos.service.ts(ratePhoto方法)

public ratePhoto(photoId: number, ratePhotoDto: RatePhotoDto, user: User): Observable<any> {
    return this.getPhoto(photoId).pipe(
        switchMap((photo: Photo) => from(this.photoRatingRepository.findOneBy({ photo: { id: photo.id }, user: { id: user.id } })).pipe(
            switchMap((photoRating: PhotoRating) => {
                // 处理评分的新增或更新
                const rating$ = !photoRating 
                    ? from(this.photoRatingRepository.save({
                        rate: ratePhotoDto.rate,
                        user,
                        photo
                      }))
                    : from(this.photoRatingRepository.save({
                        ...photoRating,
                        rate: ratePhotoDto.rate
                      }));

                // 保存评分后,更新当前用户对该照片的所有评论的评分关联
                return rating$.pipe(
                    switchMap((savedRating) => from(this.photoCommentRepository.findBy({ 
                        photo: { id: photoId }, 
                        user: { id: user.id } 
                    })),
                    switchMap((comments) => {
                        const updatedComments = comments.map(comment => ({
                            ...comment,
                            photoRating: savedRating
                        }));
                        return from(this.photoCommentRepository.save(updatedComments));
                    }),
                    map(() => ({ success: true, message: '评分及关联评论更新完成' }))
                );
            })
        )
    );
}
补充说明
  • 新增PhotoComment与User的关联,确保能精准定位当前用户对目标照片的所有评论
  • 修正外键列名与关联字段命名,符合TypeORM关联规范
  • 在评分保存后,批量更新对应评论的photoRating关联,确保评论能同步显示最新评分
  • cascade: true配置可确保PhotoRating变更时,关联评论自动同步,但手动更新关联关系更可控、直观

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 14:54:55