Spring

엔티티 상속 @Inheritance @DiscriminatorColumn

MDanderson 2023. 11. 9. 21:21

 

이 코드는 JPA(Java Persistence API)를 사용하여 데이터베이스 테이블 상속을 구현하고 있습니다. @Inheritance와 @DiscriminatorColumn 어노테이션은 상속 관계에 있는 엔티티들을 데이터베이스에 어떻게 매핑할지 정의합니다.

@Inheritance(strategy = InheritanceType.SINGLE_TABLE):
@Inheritance 어노테이션은 엔티티 상속 전략을 지정하는 데 사용됩니다. InheritanceType.SINGLE_TABLE 전략은 모든 상속받는 클래스들이 하나의 테이블에 매핑되는 것을 의미합니다. 즉, 부모 클래스 Authentication과 모든 자식 클래스들의 데이터가 단일 데이터베이스 테이블에 저장됩니다.
예를 들어, BasicAuthentication과 OAuth2Authentication 두 자식 클래스가 있다고 가정할 때, Authentication 테이블 하나에 두 클래스의 모든 필드가 컬럼으로 포함되어 있게 됩니다.


@DiscriminatorColumn(name = "authentication_type"):
@DiscriminatorColumn은 단일 테이블 상속 전략을 사용할 때, 하위 클래스들을 구분하기 위한 컬럼을 지정합니다. name = "authentication_type"는 데이터베이스 테이블에 authentication_type이라는 이름의 컬럼을 추가하며, 이 컬럼은 각 행(row)이 어떤 하위 클래스의 인스턴스에 해당하는지를 나타냅니다.
예를 들어, BasicAuthentication 인스턴스는 authentication_type 컬럼에 BASIC_AUTH라는 값을 가지고, OAuth2Authentication 인스턴스는 다른 값을 가지게 됩니다.
이 코드에서 사용된 Authentication 클래스는 추상 클래스이므로, 직접적으로 인스턴스를 생성할 수 없습니다. 대신, 이 클래스를 상속받는 구체적인 자식 클래스의 인스턴스가 생성되어 데이터베이스에 저장될 때 authentication_type 컬럼을 사용하여 어떤 타입의 인증인지 구분할 수 있습니다.

간단한 예시:
데이터베이스에 Authentication 테이블이 하나 있고, 이 테이블에는 id, member_id, authentication_type 등의 컬럼이 있습니다.
BasicAuthentication 클래스와 OAuth2Authentication 클래스가 Authentication 클래스를 상속받습니다.
BasicAuthentication 인스턴스가 데이터베이스에 저장될 때, authentication_type 컬럼에는 BASIC이라는 값이 저장됩니다.
OAuth2Authentication 인스턴스가 데이터베이스에 저장될 때, authentication_type 컬럼에는 OAUTH2와 같은 다른 값을 저장하여 두 타입을 구분합니다.
이런 방식으로, 하나의 테이블을 사용하여 다형성을 데이터베이스 수준에서 표현할 수 있으며, 각 행이 어떤 타입의 엔티티인지 쉽게 식별할 수 있습니다.

 

 

------------------------------------------------------------------------

 

JPA에서 단일 테이블 상속 전략을 사용할 때 @DiscriminatorColumn을 사용하면, 하위 클래스를 구별하기 위한 컬럼이 상속받는 테이블에 추가됩니다. 이 컬럼은 각 엔티티 인스턴스가 어떤 하위 클래스 타입에 속하는지를 저장하는데 사용됩니다. 그러나, @DiscriminatorColumn이 지정되어 있으면, @Column 어노테이션을 사용하여 authenticationType 필드를 명시적으로 매핑할 필요는 없습니다.

@DiscriminatorValue 어노테이션은 하위 클래스에 선언되며, 인스턴스가 저장될 때 @DiscriminatorColumn으로 지정된 컬럼에 설정될 값을 제공합니다. 예를 들어, @DiscriminatorValue(Authentication.BASIC_AUTH)는 BasicAuthentication 엔티티의 인스턴스가 저장될 때 authentication_type 컬럼에 BASIC이라는 값을 저장하게 됩니다.

실제로 @Column 어노테이션은 필드 또는 속성을 데이터베이스 테이블의 컬럼에 매핑할 때 사용되는데, @DiscriminatorColumn이 지정된 필드에 대해 @Column을 사용하지 않아도 JPA 구현체가 자동으로 해당 컬럼을 관리합니다.

따라서 @Column(name = "authentication_type", ...) 선언은 일반적으로 필요하지 않으며, 여기서는 insertable = false, updatable = false로 설정되어 있어서 엔티티 매니저가 이 필드를 데이터베이스에 직접 삽입하거나 업데이트하지 않도록 지정되었습니다. 이는 authentication_type 컬럼이 JPA에 의해 자동으로 관리되며, 주로 @DiscriminatorValue 어노테이션에 의해 값이 할당되기 때문에 발생하는 중복 삽입이나 업데이트를 방지하기 위함입니다.

요약하자면, @Inheritance와 @DiscriminatorColumn 설정으로 이미 상속 관계와 구별 컬럼이 정의되어 있기 때문에, authenticationType 필드에 대해 @Column 어노테이션을 사용할 필요는 없습니다.

 

-----------------------------------------------------------------------------------------

 

BasicAuthentication 객체를 authentication 엔티티에 저장하는 것이 가능하고, 이는 JPA 상속 구조에서 일반적인 방식입니다.

여기서 BasicAuthentication 클래스는 Authentication 추상 클래스를 상속받습니다. JPA에서 이런 상속 구조를 사용하면, 자식 클래스의 인스턴스는 부모 클래스로 선언된 엔티티에 저장될 수 있습니다. 이 경우에는 @Inheritance(strategy = InheritanceType.SINGLE_TABLE)이 사용되었기 때문에 모든 Authentication 타입의 인스턴스들이 같은 데이터베이스 테이블에 저장됩니다.

@DiscriminatorColumn과 @DiscriminatorValue 어노테이션은 단일 테이블에 저장된 각 행이 어떤 자식 클래스의 인스턴스인지 구별하기 위해 사용됩니다. 예를 들어, BasicAuthentication 인스턴스가 데이터베이스에 저장될 때, authentication_type 컬럼은 BASIC_AUTH 값으로 설정됩니다. 이를 통해, 쿼리를 할 때 혹은 객체를 로딩할 때 JPA 구현체는 해당 컬럼의 값에 기반하여 올바른 자식 클래스 타입을 결정할 수 있습니다.

그래서 BasicAuthentication 객체를 생성하여 authenticationRepository에 저장하는 것은 올바른 방식입니다. 이렇게 하면 Authentication 테이블에 새로운 행이 추가되고, authentication_type 컬럼은 BasicAuthentication을 나타내는 BASIC_AUTH 값으로 설정됩니다.

이 방식을 사용하면 데이터베이스 내에서 다형성을 표현할 수 있으며, 객체 지향적인 방식으로 엔티티를 관리할 수 있습니다. 추가적으로, 테이블을 분리하지 않고 하나의 테이블에서 여러 타입의 인증 정보를 관리할 수 있는 장점이 있습니다.

 

--------------------------------------------------------------------

추상 클래스나 추상 메소드 자체로는 직접적인 객체를 생성할 수 없습니다. 추상 클래스는 하나 이상의 추상 메소드를 가지고 있거나, 객체 생성을 위해 abstract로 선언되어 구현되지 않은 메소드를 포함할 수 있는 클래스입니다. 이러한 클래스는 다른 클래스가 상속하고 추상 메소드를 구현할 때까지 완전한 형태가 아니므로 인스턴스화할 수 없습니다.

그러나 추상 클래스를 상속받는 하위 클래스에서 모든 추상 메소드를 구현하면, 그 하위 클래스의 객체를 생성할 수 있습니다. 이 경우, 객체는 추상 클래스 타입으로 참조될 수 있지만 실제로는 구체적인 하위 클래스의 인스턴스입니다.

 

위 예시에서 Animal은 추상 클래스이고, makeSound는 추상 메소드입니다. Dog 클래스는 Animal을 상속받고 makeSound 메소드를 구현합니다. 메인 메소드에서는 Dog 객체를 생성하고 Animal 타입의 참조로 그 객체를 다룹니다.

추상 클래스를 사용하는 목적은 일반적으로 공통의 인터페이스를 제공하고, 상속받는 클래스들이 해당 인터페이스를 구현하도록 강제하는 데 있습니다. 이를 통해 코드의 재사용성과 유지보수성을 높일 수 있습니다.