이번엔 상속 관계에 대해 알아보자.
Project, Module, Task 이 3개 객체가 있다.
최상위 객체는 Project이며, 그 자식으로 Module 이 있으며, Module의 자식으로 Task가 있다.
먼저 소스를 보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | package com.zest.hibernate.chapter5.inheritancemapping; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; @Entity //single table 실행시 stategy가 없는것과 동일한 결과를 볼수있다. @Inheritance(strategy=InheritanceType.SINGLE_TABLE) //각 class마다 table이 생성되며, 하위 class들은 pk키를 기준으로 테이블이 생성된다. //또, 최상위 클래스는 pk와 하위 컬럼만 존재한다. //@Inheritance(strategy=InheritanceType.JOINED) //class에 맞는 컬럼 값만 저장하며, pk는 최상위 클래스 값으로 중복되지 않은 값으로 저장된다. //@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public class Project { @Id @GeneratedValue private int projectId; private String projectName; public int getProjectId() { return projectId; } public void setProjectId(int projectId) { this.projectId = projectId; } public String getProjectName() { return projectName; } public void setProjectName(String projectName) { this.projectName = projectName; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | package com.zest.hibernate.chapter5.inheritancemapping; import javax.persistence.Entity; @Entity public class Module extends Project{ private String moduleName; public String getModuleName() { return moduleName; } public void setModuleName(String moduleName) { this.moduleName = moduleName; } } | cs |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package com.zest.hibernate.chapter5.inheritancemapping; import javax.persistence.Entity; @Entity public class Task extends Module{ private String taskName; public String getTaskName() { return taskName; } public void setTaskName(String taskName) { this.taskName = taskName; } } | cs |
먼저 상속에 관한 옵션은 3가지 어노테이션이 존재한다.
@Inheritance(strategy=InheritanceType.SINGLE_TABLE) - 디폴트 선언이며, 하위 자식의 값들은 무시되며, 최상위 클래스의 테이블에만 정보를 넣는다.
@Inheritance(strategy=InheritanceType.JOINED) - 이름에서 알듯이 자식들은 부모와 fk로 엮이며, 부모는 자식의 값을 가지고 있고, 자식은 자신의 값을 가지고 있는다. 결국 부모는 전체의 데이터를 가지고 있고 자식은 fk로 본인의 값들을 가지고 있는다.
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) - 부모 자식 포함해서 중복되지 않는 값을 서로간에 가지고 있는다.
아마도 제일 많이 쓰이는건 2번이 아닐까 싶다. 그럼 테스트 코드를 보자. 먼저 @Inheritance(strategy=InheritanceType.SINGLE_TABLE) 일 경우
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | package com.zest.hibernate.chapter5.inheritancemapping; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.junit.Test; public class InheritaceMappingTest { @Test public void defaultRunTableTest(){ AnnotationConfiguration config = new AnnotationConfiguration(); config.addAnnotatedClass(Project.class); config.addAnnotatedClass(Module.class); config.addAnnotatedClass(Task.class); config.configure("hibernate.cfg.xml"); new SchemaExport(config).create(true, true); // 아래 두개의 구문은 객체를 트랜잭션을 컨트롤. SessionFactory factory = config.buildSessionFactory(); Session session = factory.getCurrentSession(); session.beginTransaction(); Project p = new Project(); p.setProjectName("hibernate lessons"); Module m = new Module(); m.setProjectName("spring lessons"); m.setModuleName("aop"); Task t = new Task(); t.setProjectName("java lessons"); t.setModuleName("collections"); t.setTaskName("arraylist"); session.save(p); session.save(m); session.save(t); session.getTransaction().commit(); } } | cs |
1 2 3 4 | Hibernate: insert into TESTSCHEMA.Project (projectName, DTYPE, projectId) values (?, 'Project', ?) Hibernate: insert into TESTSCHEMA.Project (projectName, moduleName, DTYPE, projectId) values (?, ?, 'Module', ?) Hibernate: insert into TESTSCHEMA.Project (projectName, moduleName, taskName, DTYPE, projectId) values (?, ?, ?, 'Task', ?) | cs |
위의 형태로 로그가 나올 것이다. 결과를 보면 project 말고는 다른 테이블은 생성이 안될 것이다.
1 2 3 4 | drop table testschema.task; drop table testschema.module; drop table testschema.project; | cs |
다시 테이블을 드랍 시키고 @Inheritance(strategy=InheritanceType.JOINED) 이 어노테이션을 적용해보자.
1 2 3 4 5 6 7 | Hibernate: insert into TESTSCHEMA.Project (projectName, projectId) values (?, ?) Hibernate: insert into TESTSCHEMA.Project (projectName, projectId) values (?, ?) Hibernate: insert into TESTSCHEMA.Module (moduleName, projectId) values (?, ?) Hibernate: insert into TESTSCHEMA.Project (projectName, projectId) values (?, ?) Hibernate: insert into TESTSCHEMA.Module (moduleName, projectId) values (?, ?) Hibernate: insert into TESTSCHEMA.Task (taskName, projectId) values (?, ?) | cs |
Project에는 결과가 총 3개가 생성이 된다. Module에 두개의 row가 생성되며, 마지막 task에는 1개의 row가 생성 될것이다. 그리고 테이블의 구조를 살펴보면 module.projectId , task.projectId는 pk,fk로 되어있다.
마지막 @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)를 해보자. 먼저 테이블을 drop후 위에 선언한 project 객체의 주석을 변경한다. 그리고 테스트 ㄱㄱㄱㄱ
1 2 3 | Hibernate: insert into TESTSCHEMA.Project (projectName, projectId) values (?, ?) Hibernate: insert into TESTSCHEMA.Module (projectName, moduleName, projectId) values (?, ?, ?) Hibernate: insert into TESTSCHEMA.Task (projectName, moduleName, taskName, projectId) values (?, ?, ?, ?) | cs |
자신의 데이터만 row에 생길 것이다.
소스는 https://github.com/zest133/hibernateTest.git 여기에