Spring Boot 如何与JPA建立关系,以跟踪视频观看记录

czq61nw1  于 5个月前  发布在  Spring
关注(0)|答案(1)|浏览(80)

我目前正在做一个项目,它有多个程序和程序有多个视频,所以我设置我的程序和ProgramVideo实体如下。

@Entity
@SuperBuilder
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "program")
public class Program extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(name = "title")
    private String title;

    //other fields I'm using

    @OneToMany(mappedBy = "program", cascade = CascadeType.ALL)
    private List<ProgramVideo> programVideo = new ArrayList<>();

个字符
这里我没有在ProgramVideoEntity中添加@ManyToOne关系,因为我认为我不需要从ProgramVideo端获取Program信息。
在设置了ProgramVideoProgram实体之后,我想实现一种方法来跟踪用户是否开始观看视频以及他们观看视频的时间点。
为了实现这个功能,我决定为
1.在VideoRecordHistory表中创建一个条目,以指示用户是否开始/点击观看特定视频。
1.不时更新创建的条目,其中包含播放视频的时间点信息。
VideoRecordHistory实体/表如下所示。

@Entity
@SuperBuilder
@Getter
@AllArgsConstructor(access = AccessLevel.PROTECTED)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "video_record_history")
public class VideoRecordHistory extends BaseEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne(fetch = LAZY)
    @JoinColumn(name = "program_video_id")
    @JsonIgnore
    private ProgramVideo programVideo;

    @Column(name = "member_id")
    private Long memberId;

    @Column(name = "video_length")
    private String videoLength;

    @Column(name = "watched_to")
    private String watchedTo;
}


使用第一个API,创建一个具有programVideoId、memberId和videoLength的条目。
需要记住的一件事是,我没有在这个表和我的成员表之间添加任何关系,因为它会创建一个循环关系,因为它可能会导致堆栈溢出。

问题

因此,用户注册到一个程序并单击该程序以查看program_videos列表以及每个视频的进度(来自VideoRecordHistory表)。
从本质上讲,ProgramVideo VideoRecordHistory之间的关系<->是OneToMany,因为我不会为每个用户的视频历史创建一个表。我想在一个表中使用programVideoId和memberId跟踪所有记录。由于它是OneToMany,并设置为以下内容,

@OneToMany(mappedBy = "programVideo", cascade = CascadeType.ALL)
    @JsonIgnore
    private List<VideoRecordHistory> videoRecordHistoryList = new ArrayList<>();


当我使用以下查询时,

public List<ProgramVideo> getProgramVideoListAndProgressByProgramAndMember(Long programId, Long memberId) {
        return queryFactory
                .select(programVideo)
                .from(programVideo)
                .leftJoin(videoRecordHistory)
                .on(programVideo.eq(videoRecordHistory.programVideo))
                .where(
                        programVideo.program.id.eq(programId),
                        videoRecordHistory.memberId.eq(memberId)
                )
                .fetch();
    }


它总是期望一个videoRecordHistory列表AND给我所有用户的记录,而不使用此行过滤掉特定成员

videoRecordHistory.memberId.eq(memberId)


我尝试的另一个查询是

public List<ProgramVideo> getProgramVideoListAndProgressByProgramAndMember(Long programId, Long memberId) {
        return queryFactory
                .select(programVideo)
                .from(programVideo)
                .leftJoin(videoRecordHistory)
                .on(programVideo.eq(videoRecordHistory.programVideo)
                        .and(videoRecordHistory.memberId.eq(memberId))
                )
                .where(
                        programVideo.program.id.eq(programId)
                )
                .fetch();
    }


它在'ON'子句中添加了videoRecordHistory成员约束。这给了我与之前查询所有成员的视频历史记录相同的结果...

问题

我想使用ProgramId获取ProgramVideo列表,使用memberId获取特定用户的进度。
1.我不知道我对查询的使用是否错误

或者

1.我不知道我的实体设置是否无效,需要修复。
我认为将VideoRecordHistory作为Programvideo实体中的List是导致问题的原因,强制结果总是一个列表,而且,即使有memberId约束,我仍然会获得所有成员的记录。

更新

原始查询:

2023-12-20T14:25:50.671+09:00 DEBUG 99522 --- [nio-8080-exec-2] org.hibernate.SQL                        : 
    select
        p1_0.id,
        p1_0.created_at,
        p1_0.created_id,
        p1_0.day_count,
        p1_0.has_assignment,
        p1_0.media_url,
        p1_0.program_id,
        p1_0.title,
        p1_0.updated_at,
        p1_0.updated_id,
        p1_0.video_point,
        p1_0.video_summary,
        p1_0.video_thumbnail 
    from
        program_video p1_0 
    left join
        video_record_history v1_0 
            on p1_0.id=v1_0.program_video_id 
            and v1_0.member_id=? 
    where
        p1_0.program_id=?
Hibernate: 
    select
        p1_0.id,
        p1_0.created_at,
        p1_0.created_id,
        p1_0.day_count,
        p1_0.has_assignment,
        p1_0.media_url,
        p1_0.program_id,
        p1_0.title,
        p1_0.updated_at,
        p1_0.updated_id,
        p1_0.video_point,
        p1_0.video_summary,
        p1_0.video_thumbnail 
    from
        program_video p1_0 
    left join
        video_record_history v1_0 
            on p1_0.id=v1_0.program_video_id 
            and v1_0.member_id=? 
    where
        p1_0.program_id=?

mi7gmzs6

mi7gmzs61#

查看Hibernate SQL,我意识到它只查询属于program_video的列,所以我使用Projection.fields方法来定制输出的每一列

解决方案

所以我做了一个像下面这样的DTO

@Getter
@SuperBuilder
@NoArgsConstructor
public class ProgramVideoAndProgressResponseDto {
    private String title;
    private String videoThumbnail;
    private String videoLength;
    private String watchedTo;
    private CompletionStatus completionStatus;

字符串
并将其实现到我的查询中:

return queryFactory
                .select(Projections.fields(ProgramVideoAndProgressResponseDto.class,
                        programVideo.title,
                        programVideo.videoThumbnail,
                        videoRecordHistory.videoLength,
                        videoRecordHistory.watchedTo
                        ))
                .from(programVideo)
                .leftJoin(videoRecordHistory)
                .on(programVideo.eq(videoRecordHistory.programVideo)
                        .and(videoRecordHistory.memberId.eq(memberId))
                )
                .where(
                        programVideo.program.id.eq(programId)
                )
                .fetch();
    }

相关问题