Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,13 @@
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;


public interface AttendanceCodeRepository extends JpaRepository<AttendanceCode, Long> {
public interface AttendanceCodeRepository extends JpaRepository<AttendanceCode, Integer> {

// [추가] 모든 활성화된 코드를 한 번에 만료 처리 (벌크 연산)
@Modifying
Expand All @@ -34,4 +33,3 @@ public interface AttendanceCodeRepository extends JpaRepository<AttendanceCode,
List<AttendanceCode> findByAttendanceDate(LocalDate attendanceDate);
}


Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
package com.example.Piroin.project.domain.attendance.repository;

import com.example.Piroin.project.domain.attendance.entity.AttendanceCode;
import com.example.Piroin.project.domain.curriculum.entity.StudySession;
import com.example.Piroin.project.domain.user.entity.User;
import com.example.Piroin.project.domain.attendance.entity.Attendance;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import java.time.LocalDate;
import java.util.List;
import java.util.Optional;

public interface AttendanceRepository extends JpaRepository<Attendance, Long> {
public interface AttendanceRepository extends JpaRepository<Attendance, Integer> {

Optional<Attendance> findById(Integer id);


// 연관관계 필드명이 attendanceCode 라면 내부 ID인 Id를 조합하여 명명
Optional<Attendance> findByUserIdAndAttendanceCodeId(Long userId, Long attendanceCodeId);


int countByUserAndStatusFalse(User user);

// 1. 특정 출석 코드 ID에 해당하는 결석 데이터 조회
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public AttendanceMarkResponse markAttendance(Long userId, String inputCode) {
// 혹은 조회된 code의 날짜/차수 정보를 기반으로 기존 출석 기록을 찾아야 합니다.
// (여기서는 이전 답변 시나리오 1인 'attendanceCodeId'로 매핑했다고 가정했을 때의 예시입니다.)
Attendance attendance = attendanceRepository
.findByUserIdAndAttendanceCodeId(userId, Long.valueOf(code.getId()))
.findByUserIdAndAttendanceCodeId(userId, code.getId())
.orElse(null);

// 해당 사용자와 출석 코드에 대한 출석 기록이 존재하지 않는 경우
Expand Down Expand Up @@ -323,4 +323,3 @@ public List<AttendanceStatusRes> findByUserId(Integer userId) {


}

Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import java.util.List;
import java.util.Optional;

public interface DepositRepository extends JpaRepository<Deposit, Long> {
public interface DepositRepository extends JpaRepository<Deposit, Integer> {
Optional<Deposit> findByUser(User user);

Optional<Deposit> findByUserId(Long userId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.example.Piroin.project.domain.question.entity;

import com.example.Piroin.project.domain.user.entity.User;
import com.example.Piroin.project.domain.user.enums.Role;
import jakarta.persistence.*;
import lombok.*;

Expand All @@ -11,12 +12,12 @@
name = "question_anonymous_identity",
uniqueConstraints = {
@UniqueConstraint(
name = "uq_question_anon_question_user",
name = "uq_question_anonymous_identity_question_user",
columnNames = {"question_id", "user_id"}
),
@UniqueConstraint(
name = "uq_question_anon_question_no",
columnNames = {"question_id", "anonymous_no"}
name = "uq_question_anonymous_identity_question_role_no",
columnNames = {"question_id", "role", "anonymous_no"}
)
}
)
Expand All @@ -41,7 +42,10 @@ public class QuestionAnonymousIdentity {
@Column(name = "anonymous_no", nullable = false)
private Integer anonymousNo;

@Enumerated(EnumType.STRING)
@Column(name = "role", nullable = false)
private Role role;

@Column(name = "created_at", nullable = false)
private LocalDateTime createdAt;
}

Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,37 @@
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;
import java.util.Set;

public interface QuestionAnonymousIdentityRepository extends JpaRepository<QuestionAnonymousIdentity, Long> {

// 해당 질문에서 유저의 익명 번호 조회
// 용도: 댓글 작성 시 이미 번호가 있는지 확인
Optional<QuestionAnonymousIdentity> findByQuestionAndUser(Question question, User user);

// 해당 질문에서 특정 역할(MEMBER/ADMIN)의 익명 번호 수 조회
// 용도: 새 익명 번호 발급 시 역할별로 따로 카운트
// MEMBER → 익명1, 익명2... / ADMIN → 운영진1, 운영진2...
int countByQuestionAndUser_Role(Question question, Role role);
// 질문 상세 조회용: 댓글 작성자들의 익명 번호를 한 번에 조회
@Query("""
SELECT identity
FROM QuestionAnonymousIdentity identity
JOIN FETCH identity.user
WHERE identity.question = :question
AND identity.user.id IN :userIds
""")
List<QuestionAnonymousIdentity> findByQuestionAndUserIds(
@Param("question") Question question,
@Param("userIds") Set<Long> userIds
);

@Query("SELECT COALESCE(MAX(a.anonymousNo), 0) FROM QuestionAnonymousIdentity a " + "WHERE a.question = :question AND a.user.role = :role")
@Query("""
SELECT COALESCE(MAX(identity.anonymousNo), 0)
FROM QuestionAnonymousIdentity identity
WHERE identity.question = :question
AND identity.role = :role
""")
int findMaxAnonymousNoByQuestionAndRole(
@Param("question") Question question,
@Param("role") Role role
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,19 @@

public interface QuestionCommentRepository extends JpaRepository<QuestionComment, Long> {
/*
특정 질문의 삭제되지 않은 최상위 댓글 목록(등록순)
parentComment가 null인 것 = 대댓글이 아닌 최상위 댓글
용도: 질문 상세 페이지에서 댓글 목록 표시 시
질문 상세 조회용 댓글 목록을 한 번에 가져온다.
댓글 작성자와 부모 댓글을 함께 로딩해 댓글/대댓글 DTO 조립 중 N+1 조회를 피한다.
*/
List<QuestionComment> findByQuestionAndParentCommentIsNullAndDeletedAtIsNullOrderByCreatedAtAsc(Question question);
@Query("""
SELECT comment
FROM QuestionComment comment
JOIN FETCH comment.user
LEFT JOIN FETCH comment.parentComment
WHERE comment.question = :question
AND comment.deletedAt IS NULL
ORDER BY comment.createdAt ASC, comment.id ASC
""")
List<QuestionComment> findByQuestionWithUserAndParentComment(@Param("question") Question question);

/*
질문 목록 미리보기용 최상위 댓글 3개를 질문별로 한 번에 조회한다.
Expand All @@ -25,7 +33,7 @@ public interface QuestionCommentRepository extends JpaRepository<QuestionComment
SELECT ranked.question_id AS "questionId",
ranked.id AS "commentId",
ranked.user_id AS "userId",
u.role AS "userRole",
COALESCE(qai.role, u.role) AS "userRole",
ranked.content AS "content",
ranked.image_url AS "imageUrl",
ranked.created_at AS "createdAt",
Expand Down Expand Up @@ -64,12 +72,6 @@ WHERE qc.question_id IN (:questionIds)
""")
List<CommentCountRow> countByQuestionIds(@Param("questionIds") List<Long> questionIds);

/*
특정 댓글의 대댓글 목록(등록순)
용도: 댓글 아래 대댓글을 가져올 때
*/
List<QuestionComment> findByParentCommentAndDeletedAtIsNullOrderByCreatedAtAsc(QuestionComment parentComment);

interface PreviewCommentRow {
Long getQuestionId();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

import com.example.Piroin.project.domain.curriculum.entity.StudySession;
import com.example.Piroin.project.domain.question.entity.Question;
import jakarta.persistence.LockModeType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Lock;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;

import java.util.List;
import java.util.Optional;
Expand All @@ -19,4 +23,28 @@ public interface QuestionRepository extends JpaRepository<Question, Long> {
용도: 질문 상세 조회, 수정, 삭제, 좋아요 처리 시
*/
Optional<Question> findByIdAndDeletedAtIsNull(Long id);
}

/*
질문 상세 조회용: 질문 작성자를 함께 가져와 상세 DTO 조립 중 추가 조회를 피한다.
*/
@Query("""
SELECT question
FROM Question question
JOIN FETCH question.user
WHERE question.id = :id
AND question.deletedAt IS NULL
""")
Optional<Question> findDetailByIdAndDeletedAtIsNull(@Param("id") Long id);

/*
좋아요 카운트 갱신용: 같은 질문에 대한 동시 토글 요청을 직렬화해 likeCount lost update를 방지한다.
*/
@Lock(LockModeType.PESSIMISTIC_WRITE)
@Query("""
SELECT question
FROM Question question
WHERE question.id = :id
AND question.deletedAt IS NULL
""")
Optional<Question> findByIdAndDeletedAtIsNullForUpdate(@Param("id") Long id);
}
Loading
Loading