관계형 DB에서 엔티티간 연관관계를 맺는것은 , 데이터 모델 설계와도 관련된 중요한 내용이며

JPA에서도 설계된 연관관계를 CLASS OBJECT로 맵핑처리 하는것은 아주 중요한 내용입니다.


데이터 중심 접근  VS 객체지향 접근

사용자와 주소테이블이 분리되었고

사용자정보와  주소정보를 각각 가져온다라고 가정해봅시다.

데이터 중심

User user =  sql.exec( User , "select * from user u where u.id=", 1234 );
.....
Address address = sql.exec( Address , "select t.* from address t join user u on u.addressid = " + user.addressid  );

사용자 정보를 조회하고, 사용자 테이블에 등록된 외래키인 addressid를 가지고

주소 정보를 한번더 탐색해야 우리가 원하는 User와 Address정보가 각각 완성이 됩니다.

사용자정보는 단지 주소엔티티의 외래키만 가지고 있을뿐입니다.

위와같이 쿼리를 두번호출하는 방식은 데이터관점에서 성능적으로 잘못되었고 

처음부터 조인을 걸고 User정보에 Address가 가진 각각 컬럼정보를 모두 포함해야하는 방식을 선택한다고 해도

ERD가 표현할수 있는 엔티티 연관정보를 UML에서 표현하지 못함을 의미합니다.   


객체중심

User user = em.find( User , 1234 );
.....
Address address = user.getAddress();

객체는 조인처리 대신, 참조를 얻을수 있어야합니다.  JPA는 실제 데이터조회를 위와같이 이용을 합니다.

사용자를 통해 주소의 참조값을 얻을수 있기때문에   

데이터베이스의 ERD와 ,객체를 표현하는 UML의 아주 큰차이가 좁혀졌습니다. 


하지만 데이터를 객체중심 접근방법을 사용하기위해서는 각종 연관키가 설정된 엔티티를 ,

참조형태의 객체모델로 변환하는 방법을 알아야합니다. 이것은 생각보다 여려우며

외래키를 사용하여 조인을 걸어 연관 객체를 얻어오는것은 여러차례의 SQL문을 통해 성공하고 사용될수 있으나

JPA에서는 테이블에 걸려있는 연관키를 파악하고 머릿속에 정확한 ERD를 그려내지 못하면

참조를 얻는것은 실패할것입니다.


연관관계를 고혀한 Entity 설계

ERD(데이터베이스)의 엔티티와 UML(어플리케이션)의 연관성 정보를 일치시키면서

객체지향접근 방법을 사용하여 데이터를 제어하기위해서는 섬세한 작업이필요합니다.


외래키를 통해 이루어지는  연관 속성을 , 객체에도 반영을 하려면 연관성을 의미하는

몇가지 단어를 간략하게 정리 해보겠습니다.

연관관계 주요속성

  • ManyToOne : N VS 1 관계
  • OneToMany : 1 VS N 관계
  • ManyToMany : N VS N 관계

연관관계방향

  • 단방향 : 다른 엔티티를 한쪽방향으로 참조하여 접근가능함을 의미합니다.
  • 양방향 : 엔티티간 상호 참조가 있어서 양방향 참조가능함을 의미합니다.

키 전이에따른 구분

  • 식별 : 부모의 키를 자식,손자에게 계속 전파하면서 복합키가 발생
  • 비식별 : 부모의 대리키만 사용함으로 단일키처리 


ManyToOne




CREATE TABLE `group_info` (
  `group_id` int(11) NOT NULL AUTO_INCREMENT,
  `namevarchar(255) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`group_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
 
 
CREATE TABLE `user` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `email` varchar(255) COLLATE utf8_bin DEFAULT NULL,
  `namevarchar(255) COLLATE utf8_bin DEFAULT NULL,
  `group_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`user_id`),
  KEY `FKa36i4ekojwk70bxen390i6tek` (`group_id`),
  CONSTRAINT `FKa36i4ekojwk70bxen390i6tek` FOREIGN KEY (`group_id`) REFERENCES `group_info` (`group_id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COLLATE=utf8_bin;



외래키로 설정된 두 테이블의 엔티티입니다. 사용자가 여러명있고 그룹은 여러명의 사용자를

가질수 있기때문에   N : 1 관계 입니다.

선언

클래서 정의 코드내에서는 '@ManyToOne' 어노테이션 설정을통해 연관관계를 설정을 하기만하면됩니다.

데이터베이스와 유사하게 몇가지 제약조건( 널허용 )을 적용 하는것도 가능합니다.

@Entity
public class User {
    @Id
    @GeneratedValue
    @Column(name = "USER_ID")
    private Integer id;
 
    private String name;
 
    private String email;
  
    @ManyToOne
    @JoinColumn(name = "GROUP_ID", nullable=true )
    private GroupInfo groupInfo;   
}

관련소스:http://git.webnori.com/projects/WEBF/repos/spring_jpa/browse/src/main/java/com/example/demo/data2/User.java


사용예

로직순서:

  • 존재하는 그룹을 찾는다.
  • 사용자를 등록하고, 찾은 그룹을 지정한다.
  • 사용자를 찾고, 지정된 그룹을 조회한다.
GroupInfo someGroup = groupRepository.findByName("학생");


//저장시
User addUser = new User();
addUser.setName("minsu");
addUser.setEmail("test@x.com");
addUser.setGroupInfo(someGroup);


//조회시
User someUser =  userRepository.findByName("minsu")
GroupInfo someUserMyGroup = someUser.getGroupInfo();

객체 지향적으로 접근을 한 예입니다. 데이터 베이스가 가진 정보를 단순하고 직관적이게 접근을 할수 있습니다.


기존방식의 문제:

위 로직을, 전통적인 방법으로 어플리케이션내에서  SQL/SP문으로 각각 처리한다라고 가정하면 ,

JAVA코드내에 SQL문이 썩여서 처리되거나, 별도의 관리 공간에 코드를 분리하거나? 처리가 된다고 해도 ,

사용자의 객체로부터 그룹참조를 얻어내는것은 어려울수 있습니다. 또한 약간의 옵션변경에따라 다른기능을하는,

거의 중복에 가까운 유사 SQL문 반복 작성을 해야할수도 있습니다.



추가 참고 사이트 : 




  • No labels