이번엔 level 10만 구현하면 되지만 양이 엄청 많다..
Member
<MemberRepository>
package backend.likelion.todos.member;
import java.util.Optional;
import org.springframework.stereotype.Repository;
@Repository
public interface MemberRepository <Member, Long>{
// TODO [10단계] JpaRepository를 상속받습니다.
// TODO [10단계] 아래는 기존 코드입니다. 컴파일 오류가 발생하고 있는데, 이를 해결하세요.
Optional<Member> findByUsername(String username);
}
JpaRepository를 상속받는다. 이 때 제네릭타입을 명시해주어야한다.
또한 인터페이스에는 메서드의 구현을 작성하면 안되니까 선언만 해주었다.
Optional을 하면 null값을 받을 수 있다.
<Member>
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
// TODO [10 단계] : 롬봉을 통해 기본 생성자를 PROTECTED 접근 제한자로 생성하세요.
// TODO [10 단계] : Member 객체를 Entity 로 정의하세요.
@NoArgsConstructor은 롬복을 이용하여 기본 생성자를 만드는 것이다. 이는 protected로 선언하였다.
또한 @Entity로 member을 엔티티로 선언하였다.
// TODO [10 단계] : id를 PK, Auto Increment로 설정하세요.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
Id를 @Id 어노테이션을 통해 구현하였다. 또한 @GeneratedValue 어노테이션의 strategy 속성을 GenerationType.IDENTITY로 설정하면, 데이터베이스가 자동으로 id 값을 증가시킨다.
// TODO [10 단계] : 아이디는 unique 제약 조건이 필요합니다.
@Column(unique = true)
private String username;
private String password;
private String nickname;
private String profileImageUrl;
username이 아이디이니까 여기다가 @Column을 사용해서 unique제약 조건을 넣었다.
Goal
<GoalRepository>
package backend.likelion.todos.goal;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface GoalRepository extends JpaRepository<String,Long> {
// TODO [10단계] JpaRepository를 상속받습니다.
// TODO [10단계] 아래는 기존 코드입니다. 컴파일 오류가 발생하고 있는데, 이를 해결하세요.
List<Goal> findAllByMemberId(Long memberId) ;
}
위와 마찬가지로 제네릭타입을 명시하고, 메서드 선언한 부분을 제거하였다.
<Goal>
@Getter
// TODO [10 단계] : 롬봉을 통해 기본 생성자를 PROTECTED 접근 제한자로 생성하세요.
@NoArgsConstructor(access = AccessLevel.PROTECTED)
// TODO [10 단계] : Goal 객체를 Entity 로 정의하세요.
@Entity
public class Goal {
// TODO [10 단계] : id를 PK, Auto Increment로 설정하세요.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String color;
위에 member과 같이 구현하였다.
// TODO [10 단계] : goal 과 member와의 관계를 설정합니다. (join 하는 컬럼명은 member_id로 설정합니다.), 지연 로딩을 사용합니다.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id")
private Member member;
goal과 member과의 관계를 설정한다.
지연로딩을 하여 필요한 시기에 데이터를 가져오도록 하였다. 이는 FetchType.LAZY를 사용하여 지연로딩을 구현하였고, 한 member에 여러개의 goal이 들어갈 수 있기 때문에 ManyToOne 어노테이션을 썼다.
또한 JoinColumn으로 join하는 컬럼명을 설정하였다.
Todo
<TodoRepository>
package backend.likelion.todos.todo;
import java.util.List;
import org.antlr.v4.runtime.atn.SemanticContext.AND;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
@Repository
public interface TodoRepository extends JpaRepository<Todo,Long>{
// TODO [10단계] JpaRepository를 상속받습니다.
/**
* TODO [10단계] 아래는 기존 findAllByMemberIdAndDate 코드와 동일한 역할을 합니다.
* 해당 기능을 완성하세요.
*
* 메서드의 이름만으로는 해결할 수 없습니다.
* 직접 JPQL을 작성해야 합니다.
* 어떤 어노테이션을 사용해야 할까요?
*
* JPQL 수도코드
* - TODO 와 Goal을 조인합니다.
* - 조건 : goal의 memberId 가 주어진 인자의 memberId와 동일
* AND Todo의 date의 YEAR 부분이 주어진 인자의 year와 동일 (hint: YEAR(date) 시 date의 년도 부분이 나온다.)
* AND Todo의 date의 MONTH 부분이 주어진 인자의 month와 동일 (hint: MONTH(date) 시 date의 년도 부분이 나온다.)
* - 정렬 Todo의 date의 DAY 부분을 오름차순으로. (hint: DAY(date) 시 date의 년도 부분이 나온다.)
*/
@Query("""
SELECT t
FROM Todo t
JOIN t.goal g
ON t.goal = g
WHERE g.member.id = :memberId
AND YEAR(t.date) = :year
AND MONTH(t.date) = :month
ORDER BY DAY(t.date) ASC
""")
List<Todo> findAllByMemberIdAndDateOrderByDayAsc(Long memberId, int year, int month);
}
이번엔 단순히 상속받고, 메서드 삭제만 하면 끝나는 것이 아니라 join을 위한 쿼리문도 작성해야한다.
todo와 goal을 조인하고, @Query 어노테이션을 사용한다.
<Todo>
package backend.likelion.todos.todo;
import backend.likelion.todos.common.ForbiddenException;
import backend.likelion.todos.goal.Goal;
import backend.likelion.todos.member.Member;
import jakarta.persistence.*;
import java.time.LocalDate;
import lombok.AccessLevel;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
// TODO [10 단계] : 롬봉을 통해 기본 생성자를 PROTECTED 접근 제한자로 생성하세요.
// TODO [10 단계] : Todo 객체를 Entity 로 정의하세요.
@Entity
public class Todo {
// TODO [10 단계] : id를 PK, Auto Increment로 설정하세요.
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String content;
private LocalDate date;
// TODO [10 단계] : todo 와 goal 과의 관계를 설정합니다. (join 하는 컬럼명은 goal_id로 설정합니다.), 지연 로딩을 사용합니다.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "goal_id")
private Goal goal;
private boolean isCompleted;
public Todo(String content, LocalDate date, Goal goal) {
this.content = content;
this.date = date;
this.goal = goal;
this.isCompleted = false;
}
public void validateMember(Member member) {
if (!this.goal.getMember().equals(member)) {
throw new ForbiddenException("해당 투두에 대한 권한이 없습니다.");
}
}
public void update(String content, LocalDate date) {
this.content = content;
this.date = date;
}
public void check() {
this.isCompleted = true;
}
public void uncheck() {
this.isCompleted = false;
}
}
위에 클래스들과 동일한 방식으로 구현하였다. 이번엔 join할 때 @ManyToOne을 사용하였다.
완료!
'Back-end > 멋쟁이사자처럼' 카테고리의 다른 글
[멋쟁이 사자처럼] level7~9 구현 (0) | 2024.04.30 |
---|---|
[멋쟁이사자처럼] level6 구현 (0) | 2024.04.02 |
[멋쟁이사자처럼] 질문 정리 과제 (0) | 2024.03.27 |
[멋쟁이사자처럼] 키워드 정리 과제 (0) | 2024.03.27 |
[멋쟁이사자처럼] level5 구현 (0) | 2024.03.19 |