[Dining-together] JPA Entity 상속

Jifrozen·2021년 6월 3일
0

Dining-together

목록 보기
8/25

JPA entity 상속

1. 각각의 테이블로 변환하는 조인 전략(JOINED)

  • 가장 많이 쓰는 방식이다.
  • 부모 entity의 pk를 자식 entity가 pk이자 외래키로 사용한다.
  • 정규화가 된 모델링을 사용하기 때문에 데이터 중복이 없다.

2. 통합 테이블로 변환하는 단일 테이블 전략(SINGLE_TABLE)

  • 자식 entity 값을 모두 부모 entity 속성으로 합치는 방식이다.
  • 한테이블에 있으니 성능이 좋다.
  • 서비스 규모가 크지 않을때 사용한다.

3. 서브타입 테이블로 변환하는 구현 클래스마다 테이블을 생성하는 전략(TABLE_PER_CLASS)

  • TABLE_PER_CLASS 방식은 부모의 속성들을 자식 테이블의 속성으로 갖는 방식입니다.
  • 이 경우 join을 사용하지 않고 union을 사용하는데, union 쿼리는 사용하지 않는 것이 좋으므로 이 전략은 잘 사용하지 않는다.

나는 프로젝트에 조인 전략을 선택했다.

spring security 와 jpa 상속을 같이 어떻게 쓰는지 고민했는데 그냥 위에 방식대로 사용하면 된다.

entity

@Builder
@Entity
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
@Table(name = "user")
@ApiModel(description = "사용자 상세 정보를 위한 도메인 객체")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name="type")
public class User implements UserDetails {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private long id;

	@Email
	@Column(nullable = false, unique = true, length = 100)
	private String email;

	@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
	@Column(length = 100)
	@ApiModelProperty(notes = "패스워드을 입력해 주세요")
	private String password;

	@Column(length = 100)
	@Size(min = 2, message = "Name은 2글자 이상 입력.")
	@ApiModelProperty(notes = "사용자 이름을 입력해 주세요")
	private String name;

	// @Column(length = 100)
	// private String phoneNo;

	@Past
	@ApiModelProperty(notes = "등록일 정보입니다. 자동으로 입력됩니다.")
	private Date joinDate;

	@Column(length=100)
	private String provider;

	@ElementCollection(fetch = FetchType.EAGER)
	@Builder.Default
	private List<String> roles = new ArrayList<>();

	@Column(name = "createdDate")
	@ApiModelProperty(notes = "테이블의 생성일 정보입니다. 자동으로 입력됩니다.")
	public Date createdDate;

	@Column(name = "updatedDate")
	@ApiModelProperty(notes = "테이블의 수정일 정보입니다. 자동으로 입력됩니다.")
	public Date updatedDate;

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return this.roles.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
	}

	@PrePersist
	void joinDate() {
		this.joinDate = this.createdDate = this.updatedDate = new Date();
	}

	@PreUpdate
	void updateDate() {
		this.updatedDate = new Date();
	}

	//  json 출력 안함
	@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
	@Override
	public String getUsername() {
		return this.email;
	}

	/**
	 * 아래는
	 * 로직 추가 작성 필요한 부분
	 */
	//  계정이 만료가 안됐는지
	@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	//  계정이 잠기지 않았는지
	@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	//  계정 패스워드가 만료 안됐는지
	@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	//  계정 사용 가능한지
	@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
	@Override
	public boolean isEnabled() {
		return true;
	}
}
@Entity
@DiscriminatorValue("STORE")
public class Store extends User {

	private String s_name;

	private String description;
	private String addr;
	private String s_phone;

}

Repository

public interface UserRepository<T extends User> extends JpaRepository<T, Long> {
	@Override
	Optional<T> findById(Long id);

	Optional<T> findByEmail(String email);

	Optional<T> findByEmailAndProvider(String email, String provider);
}

참고문서

https://ict-nroo.tistory.com/128
https://victorydntmd.tistory.com/209
https://stackoverflow.com/questions/51218227/user-class-for-spring-security-application

0개의 댓글