객체지향 설계는 자율적인 객체들의 협력으로 형상화된다. 객체들간의 협력을 표현하기 위해 그들간 관계를 표현해주는 수단이 바로 연관관계이다.

참조할 객체를 멤버로 설정하여 연관관계를 형성하고 이는 DB상에서 외래키로 매핑된다.
User
@Entity
@Getter
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "member_id")
private Long id;
private String username;
@ManyToOne
@JoinColumn(name="team_id")
private Team team;
}
Team
@Entity
@Getter
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "team_id")
private Long id;
private String name;
}

앞선 단방향 관계에서 양방향 관계로 전환할 경우 Team 에 User컬렉션 필드가 추가된다.
@Entity
@Getter
public class Team {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "team_id")
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<User> users = new ArrayList<>();
}
user.team_id 외래 키 하나로 양방향 연관관계를 가진다. (양쪽으로 조인 가능)SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
SELECT *
FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID
따라서 두 테이블중 한 곳에서 외래 키를 관리해야 한다.
mappedBy 속성을 사용하지 않음mappedBy 속성으로 주인 지정User 가 연관관계의 주인(User.team )이다.연관관계의 주인에 값을 입력하지 않는 경우이다.
Team team = new Team();
team.setName("teamA");
User user = new User();
user.setName("user1");
// 주인이 아닌 쪽만 연관관계 설정
team.getUsers().add(user);
순수한 객체 관계를 고려하면 아래와 같이 항상 양쪽 다 값을 설정해주어야 한다.
Team team = new Team();
team.setName("teamA");
User user = new User();
user.setName("user1");
team.getUsers().add(user);
user.setTeam(team); // 연관관계의 주인에 값 설정
DB에 진입했다가 나올 경우 JPA 상에서 자동으로 처리되는 경우가 있으나 그래도 설정하는 것이 좋다.
setter 보다 별도의 명명된 메서드를 설정해주는 것이 의미를 분명히 하기에 바람직하다.public class User {
// ...
public void changeTeam(Team team) {
this.team = team;
team.getUsers().add(team);
}
}
// 혹은
public class Team {
// ...
public void addUser(User user) {
user.setTeam(this);
usere.add(user);
}
}
toString 의 경우 사용하지 않는 것을 권장한다.(서로 무한 호출)


@JoinColumn 을 꼭 사용해야 한다. 그렇지 않으면 중간(조인) 테이블 방식을 사용일대다 단방향 매핑보다 다대일 양방향 매핑을 사용하는 것을 권장한다.

@JoinColumn(insertable = false, updatable = false)복잡도, 성능 면에서 더 나은 다대일 양방향을 사용하는 것을 권장한다.

다대일 단방향 매핑과 유사하다.

mappedBy 적용

주 테이블에 외래 키 양방향을 설정하는 경우와 매핑 방법이 같다.
주 테이블에 외래 키
null 적용대상 테이블에 외래 키
RDB는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다. 연결 테이블을 추가하여 일대다, 다대일 관계롤 풀어내야 한다.

객체는 컬렉션을 사용하여 다대다 관계의 표현이 가능하다.

@ManyToMany 사용@JoinTable 로 연결 테이블 지정
@ManyToMany → @OneToMany , @ManyToOne

슈퍼타입, 서브타입 논리 모델을 실제 물리 모델로 구현하는 방법은 다음과 같다.
@Inheritance(strategy = InheritanceType.XXX)@DiscriminatorColumn(name=”DTYPE”)@DiscriminatorValue(”XXX”) - default , Entity 이름
장점
단점
조인 전략 활용시 @DiscriminatorColumn 을 사용하는 것을 권장한다.

장점
단점
null 허용
권장되지 않는 전략이다.

em.find(BaseEntity) 불가)@MappedSuperClass 로 지정한 클래스만 상속 가능BaseEntity
package hellojpa;
import javax.persistence.MappedSuperclass;
import java.time.LocalDateTime;
@MappedSuperclass
public abstract class BaseEntity {
private String createdBy;
private LocalDateTime created;
private String lastModifiedBy;
private LocalDateTime lastModified;
//getter & setter
}
User
@Entity
public class User extends BaseEntity { ... }
테이블 생성
create table user (
id bigint not null,
created datetime,
createdBy varchar(255),
lastModified datetime,
lastModifiedBy varchar(255),
primary key (id)
);

@OneToMany(mappedBy="parent", cascade=CascadeType.PERSIST)

orphanRemoval = trueDELETE FROM CHILD WHERE ID = ?@OneToOne , @OneToMany 만 가능참고 - 개념적으로 부모를 제거하면 자식은 고아가 된다. 따라서 고아 객체 제거 기능을 활성화 하면
부모를 제거할 때 자식도 함께 제거된다. 이것은 CascadeType.REMOVE 처럼 동작한다.

aggregate라는 단어는 ‘모으다’, ‘집계하다’라는 의미를 가지며 도메인 주도 설계(domain driven desgin, DDD)에서는 관련된 객체들을 한데 묶거나 모아서 하나의 논리적인 단위로 취급한다는 의미로 사용된다. aggreegate는 관련된 객체들의 그룹을 형성하며, 이 그룹 안에서는 aggregate root를 중심으로 일관성을 유지하고 도메인 규칙을 적용한다. 정리하면, 한 단위로 묶여 관리되는 도메인 객체들의 집합을 aggregate라 지칭한다고 볼 수 있다.