DB연동 #12 JPA 활용하기 6 ( Foreign Key - OneToMany ) Java/Spring


순방향으로 ForeignKey 관계를 @ManyToOne 어노테이션으로 설정한 내용에 대한 내용은 아래 블로그에 정리해 놓았다 

@Entity
@Table(name="SCHOOL_TB")
public class SchoolJpaVO implements Serializable {
          
          private static final long serialVersionUID = 1L;
          
          @Id
          private                 long   Id;
          private                 String name;
          private                 String address;
          
          @ManyToOne
          @JoinColumn(name="Edu_grade" , insertable=false, updatable=false)
          GradeJpaVO gradeVO;

위에서 @ManyToOne은 SchoolJpaVO 객체가 Edu_grade라는 필드에 GRADE_TB와 Foreign Key로 연결되어 있음을 의미하며 다대일 형태로 그와 관련된 객체는 GradeJpaVO라는 것을 알 수 있다 
이는 하나의 GradeJpaVO 클래스에 여러개의 SchoolJpaVO가 존재하는 것을 의미한다

그럼 Web Client의 Form으로 부터 수신받은 커맨드 객체가 SchoolJpaVO이고 Foreign Key로 GroupJpaVO 객체와 연결되어 있을 경우 SchoolJpaVo 객체를 저장하고자 할 때 어떻게 해야 할까?  방법은 간단하다 

@RequestMapping(value="/insert.do")
public ModelAndView insertDo( @RequestParam(value="grade_id", required=true)String grade_id, SchoolJpaVO school, ModelAndView mav){
                   
      try {
                GradeJpaVO grade = service.getGradeById( grade_id );
                 logger.debug( grade.toString() );
                 if( grade != null ) {
                           school.setGrade(grade);
                           service.insert( school );
                 }

위에서 보는 것처럼 GradeJpaVO 객체와 관련된 grade_id는 RequestParam으로 가져오고 나머지 School 객체는 커맨드 객체형태로 Web Client로 부터 가져오면 된다
그리고 grade_id를 기준으로 Grade객체를 DB를 통하여 검색하여 가져온 후, 이를 School의 멤버변수로 설정하고 insert로 저장하면 된다

그러면 반대로 GradeJpaVO는 여러개의 SchoolJpaVO를 갖는 구조인데 이를 클래스로 어떻게 표현하는지 살펴보자

@Entity
@Table(name="GRADE_TB")
public class GradeJpaVO implements Serializable {
          private static final long serialVersionUID = 1L;

          @Id
          private  int grade;                   
          private                 String descript

         @OneToMany(fetch=FetchType.EAGER, cascade = CascadeType.ALL)
         @JoinColumn( name = "Edu_grade" )
         private List<SchoolJpaVO> schools = new ArrayList<SchoolJpa>(); 

                                    :

        public List<SchoolJpaVO> getSchools() {
                   return schools;
          }
          public void setSchools(List<SchoolJpaVO> schools) {
                   this.schools = schools;
          }


@Repository("groupDAO")
public class GroupDAO {
          
        public GroupJpaVO getGroupById( String id ) throws SQLException, Exception{
                   
                   GroupJpaVO team = em.find( GroupJpaVO.class, id);
                   return team;
          }

@OneToMay는 GradeJpaVO 객체 하나에 여러개의 SchoolJpaVO가 연결되어 있는 일대다의 의미이며, 어떠한 필드에 Foreign Key로 연결되어 있는지 @JoinColumn으로 설정해 준다  이는 앞서 SchoolJpaVO에서 선언한 것과 동일하게 Edu_grade라는 SCHOOL_TB의 필드에 Foreign Key로 연결되어 있음을 알려준다 

이제 grade를 통하여 여러개의 school를 조회할 수 있다

   public void test() {
                   AbstractApplicationContext ctx = new GenericXmlApplicationContext("classpath:ApplicationContext.xml");
                   Assert.assertNotNull(ctx);
                   
                   GroupDAO dao = ctx.getBean("groupDAO", com.book.DAO.TeamDAO.class);
                   Assert.assertNotNull( dao);

                  List <SchoolJpaVO> list;

                   try {
                             GradJpaVO grade = dao.getGradeById("1");
                             System.out.println( grade);
                             if( grade != null ) {
                                      list = grade.getSchools();
                                      for( int idx = 0; idx < list.size(); idx ++) {
                                                SchoolJpaVO school = list.get( idx );
                                                System.out.println( school );
                                      }
                             }
                   } catch (Exception e) {
                             // TODO Auto-generated catch block
                             e.printStackTrace();
                   }
다음은 역으로 Team 에 여러 Member가 존재할때 Team에 Member를 할당하고 Team 객체를 Update하는 경우의 코드이다

                  TeamVO team;

                   try {
                             team = memberService.getTeamById( team_id );
                             if(team == null) {
                                      mav.addObject("ErrorMessage", String.format( "%s id의 팀이 존재하지 않음", team_id));
                                      mav.setViewName("/testPage");
                                      return mav;
                             }
                             
                             logger.debug( team.toString() );
                             
                             for( int idx = 10; idx < 15; idx ++ ) {
                                      MemberVO temp_m = new MemberVO();
                                      temp_m.setId(String.format("0%d", idx));
                                      temp_m.setName(temp_m.getId());
                                      temp_m.setAge(11);
                                                                   
                                      temp_m.setTeam(team);
                                      
                                      team.getMembers().add( temp_m );
                             }
                             
                             List<MemberVO> list = team.getMembers();
                             for( int idx = 0; idx < list.size(); idx ++ ) {
                                      logger.debug( list.get(idx).toString() );
                             }
                             
                             memberService.updateTeam( team );
                             
                   } catch (Exception e) {
                             // TODO Auto-generated catch block
                             e.printStackTrace();
                             mav.addObject( "errorMessage", e.getMessage() );
                   }

이렇게 하면 Java의 클래스 간 멤버 클래스 관계가 DBMS에 그대로 저장이 된다 
이에 대한 로그는 아래와 같으며 member 하나당 아래 로그가 반복됨을 볼 수 있다.  

Hibernate: 
    select
        teamvo0_.id as id1_2_1_,
        teamvo0_.name as name2_2_1_,
        members1_.team_id as team_id5_1_3_,
        members1_.id as id1_1_3_,
        members1_.id as id1_1_0_,
        members1_.age as age2_1_0_,
        members1_.detail_id as detail_i4_1_0_,
        members1_.name as name3_1_0_,
        members1_.team_id as team_id5_1_0_ 
    from
        TEAM_TB teamvo0_ 
    left outer join
        MEMBER_TB members1_ 
            on teamvo0_.id=members1_.team_id 
    where
        teamvo0_.id=?
TRACE: [BasicBinder:65] binding parameter [1] as [VARCHAR] - [team3] 
TRACE: [BasicExtractor:61] extracted value ([id1_1_0_] : [VARCHAR]) - [005] 
TRACE: [BasicExtractor:61] extracted value ([age2_1_0_] : [INTEGER]) - [5] 
TRACE: [BasicExtractor:51] extracted value ([detail_i4_1_0_] : [VARCHAR]) - [null] 
TRACE: [BasicExtractor:61] extracted value ([name3_1_0_] : [VARCHAR]) - [베드로] 
TRACE: [BasicExtractor:61] extracted value ([team_id5_1_0_] : [VARCHAR]) - [team3] 
TRACE: [BasicExtractor:61] extracted value ([name2_2_1_] : [VARCHAR]) - [팀3] 
TRACE: [BasicExtractor:61] extracted value ([team_id5_1_3_] : [VARCHAR]) - [team3] 
TRACE: [BasicExtractor:61] extracted value ([id1_1_3_] : [VARCHAR]) - [005] 



1 2 3 4 5 6 7 8 9 10 다음