Mapping to Relational Databases — 실전 예시와 템플릿
예시: Academic Life System 전체 매핑
DCD → ER 매핑 과정
Step 1: DCD (Larman에서 온 것)
Step 2: 매핑 결정 테이블
| DCD 클래스 | DB 테이블 | 매핑 방식 | 비고 | |-----------|----------|----------|------| | Student | students | 1:1 | PK = student_id | | Course | courses | 1:1 | PK = course_id | | Enrollment | enrollments | 1:1 | FK: student_id, course_id | | Curriculum | curricula | 1:1 | PK: (department, year) 복합키 | | Requirement | requirements | 1:1 | FK: curriculum_id, course_id | | Prerequisite | prerequisites | 1:1 → 연결 테이블 | FK: course_id, prerequisite_course_id |
Step 3: ER Diagram
O-R 불일치가 발생하는 지점
| 불일치 | DCD에서 | DB에서 | 해결 패턴 |
|-------|--------|-------|----------|
| 참조 방식 | student.enrollments (객체 참조) | enrollments.student_id (FK) | Foreign Key Mapping |
| 다대다 | Course ↔ Prerequisite ↔ Course | 연결 테이블 필요 | Association Table Mapping |
| 컬렉션 | Student.enrollments: List | enrollments 테이블에 FK | 방향 뒤집힘 |
| 값 객체 | Money, DateRange 같은 것 | 별도 테이블? 컬럼? | Embedded Value |
템플릿
DCD → ER 매핑 워크시트
## [프로젝트명] DCD → DB 매핑
### 매핑 결정 테이블
| DCD 클래스 | DB 테이블명 | 매핑 | PK | FK | 비고 |
|-----------|-----------|------|----|----|------|
| _________ | _________ | 1:1 / 합침 / 분리 | __ | __ | |
| _________ | _________ | 1:1 / 합침 / 분리 | __ | __ | |
| _________ | _________ | 1:1 / 합침 / 분리 | __ | __ | |
### O-R 불일치 식별
| 불일치 유형 | 위치 | 해결 패턴 |
|-----------|------|----------|
| 참조 → FK | _________ | Foreign Key Mapping |
| 다대다 | _________ | Association Table Mapping |
| 상속 | _________ | Single Table / Class Table / Concrete Table |
| 값 객체 | _________ | Embedded Value / Serialized LOB |
| 컬렉션 | _________ | FK 방향 역전 |
ER Diagram 템플릿 (Mermaid)
erDiagram
[테이블1] {
[타입] [컬럼명] PK
[타입] [컬럼명]
[타입] [컬럼명]
}
[테이블2] {
[타입] [컬럼명] PK
[타입] [컬럼명] FK
[타입] [컬럼명]
}
[연결테이블] {
[타입] [컬럼명] PK
[타입] [FK1] FK
[타입] [FK2] FK
}
[테이블1] ||--o{ [테이블2] : "[관계설명]"
[테이블1] ||--o{ [연결테이블] : ""
[테이블3] ||--o{ [연결테이블] : ""
관계 기호:
||--o{: 1 대 다 (one to many)||--||: 1 대 1 (one to one)}o--o{: 다 대 다 (many to many, 연결 테이블 필요)
상속 매핑 선택 가이드
## 상속 매핑 결정
클래스 계층: [부모] → [자식A], [자식B], ...
### 평가 기준
| 기준 | Single Table | Class Table | Concrete Table |
|------|-------------|-------------|----------------|
| 구현 난이도 | 쉬움 | 중간 | 중간 |
| NULL 컬럼 | 많음 | 없음 | 없음 |
| JOIN 필요 | 없음 | 있음 (계층 깊이만큼) | 없음 |
| 공통 필드 중복 | 없음 | 없음 | 있음 |
| 다형적 쿼리 | 쉬움 (한 테이블) | 가능 (JOIN) | 어려움 (UNION) |
| 리프 클래스 쿼리 | 쉬움 | 쉬움 | 쉬움 |
### 우리 프로젝트의 상속 구조
계층: _____________
선택: _____________
근거: _____________
DDL 생성 템플릿
-- =============================================
-- [프로젝트명] Database Schema
-- 생성일: [날짜]
-- 대응 DCD: [DCD 버전/위치]
-- =============================================
-- [엔티티1] 테이블
CREATE TABLE [테이블명] (
[pk_column] [TYPE] PRIMARY KEY,
[column1] [TYPE] NOT NULL,
[column2] [TYPE],
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- [엔티티2] 테이블 (FK 참조)
CREATE TABLE [테이블명] (
id INTEGER PRIMARY KEY AUTOINCREMENT,
[fk_column] [TYPE] NOT NULL,
[column1] [TYPE] NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY ([fk_column]) REFERENCES [부모테이블]([pk_column])
);
-- [다대다 연결] 테이블
CREATE TABLE [연결테이블명] (
id INTEGER PRIMARY KEY AUTOINCREMENT,
[fk1] [TYPE] NOT NULL,
[fk2] [TYPE] NOT NULL,
FOREIGN KEY ([fk1]) REFERENCES [테이블A]([pk]),
FOREIGN KEY ([fk2]) REFERENCES [테이블B]([pk]),
UNIQUE([fk1], [fk2])
);
템플릿: 상속 매핑 전략 선택
상속이 있는 도메인 모델을 DB에 매핑할 때 사용한다.
전략 비교표
| 전략 | 테이블 수 | NULL 허용 | JOIN 필요 | 다형적 쿼리 | 리팩터링 | |------|----------|----------|----------|-----------|--------| | Single Table | 1개 | 서브 전용 필드에 NULL | 없음 | 쉬움 (한 테이블) | 쉬움 | | Class Table | N+1개 (Base + 각 Sub) | 없음 | 있음 (매 조회마다) | 가능 (JOIN) | 중간 | | Concrete Table | N개 (Sub만) | 없음 | 없음 | 어려움 (UNION) | 어려움 |
선택 기준
- 서브클래스 전용 필드가 적다 → Single Table
- 서브클래스가 자주 추가된다 → Single Table
- NULL을 절대 허용 못 한다 → Class Table
- Base 타입으로의 다형적 쿼리가 잦다 → Single Table 또는 Class Table
- 서브클래스별 독립 쿼리가 대부분 → Concrete Table
워크시트
## [프로젝트명] 상속 매핑
클래스 계층: [부모] → [자식A], [자식B], ...
| 질문 | 답변 |
|------|------|
| 서브클래스 전용 필드 수 | 적음 / 많음 |
| 서브클래스 추가 빈도 | 낮음 / 높음 |
| 다형적 쿼리 필요 | Yes / No |
| NULL 허용 | 가능 / 불가 |
> **선택**: _______________
> **근거**: _______________