Join(結合)を使用するSQLに対応したDAOクラスの適切な設計方法と実装手順
こんにちは。ゆうせいです。
新人研修中に受講者から以下の質問をいただきました。
テーブルを結合するSQLはどのDAOクラスに書くべきですか?
今回はこの質問に答えたいと思います。
システム開発において、データベースからデータを取得する処理を分離して管理する手法としてDAO(データ・アクセス・オブジェクト)パターンが広く用いられています。しかし、複数の表を繋ぎ合わせるJoin(結合)の処理を行う場合、DAOクラスをどのように設計すべきか迷う初心者の方は少なくありません。本記事では、Joinを使用したSQLを扱うDAOクラスの正しい作成方法について客観的な事実に基づき解説します。
DAOクラスとJoinの基本的な概念
DAOクラスは、データベースというデータを保管する倉庫からデータを出し入れする専任の窓口担当者にあたります。プログラムの他の部分が直接倉庫に入り込むのを防ぎ、窓口担当者に命令を出すだけで安全にデータを取得できるように設計します。
一方、Joinは複数の表を繋ぎ合わせて、ひとつのまとまったデータを生み出す操作です。高校生の皆さんに身近な例で例えると、学校の「生徒の基本情報が書かれた名簿の表」と「部活動の所属情報が書かれた表」を繋ぎ合わせて、「どの生徒が何の部活に入っているか」というひとつの新しい一覧表を作ることに相当します。
個別の表に対応するデータ管理クラスを単純に組み合わせるだけでは、結合されたデータを適切に受け取ることができません。ここまでの説明で、DAOクラスとJoinの基本的な関係性についてイメージを持っていただけたでしょうか。次に、結合データを扱う具体的な設計手法について説明します。
Joinの結果を扱う2つの設計アプローチ
Joinを使用したSQLの実行結果をDAOクラスで受け取るには、主に2つの設計方法が存在します。
アプローチ1:結合結果専用のデータ保持クラスを作成する方法
結合によって新しく生成される一覧表の項目に完全に一致させた、専用のデータ保持クラス(DTO:データ・トランスファー・オブジェクト)を定義する手法です。例えば、生徒名と部活名が結合された結果を受け取るためだけに、生徒名と部活名の2つの項目だけを持つ新しいクラスを作成します。
アプローチ2:既存のクラスを入れ子にして再利用する方法
既存の生徒クラスの中に、部活動クラスの情報をそのまま埋め込む手法です。クラスの中に別のクラスが変数として含まれる構造になります。
各アプローチの事実に基づくメリット・デメリット
各手法には、開発の規模や運用の目的状況に応じた長所と短所があります。
専用のデータ保持クラスを作成する場合のメリット・デメリット:
メリット:
- 画面や処理に必要なデータ項目だけを厳密に保持できるため、メモリの無駄が生じません。
- クラスの構造が単純であるため、データの読み書きを行うプログラムの記述が容易になります。デメリット:
- 結合を行うSQLのパターンの数だけ新しいクラスを作成する必要があり、システムの規模が大きくなると管理すべきクラスの数が膨大になります。
既存のクラスを入れ子にする場合のメリット・デメリット:
メリット:
- すでに存在するクラスを組み合わせて利用するため、新しいクラスを大量に作成する手間を削減できます。
- 生徒データの中に部活動データが含まれるという、現実の親子関係に近い形でデータを表現できます。デメリット:
- 結合の結果として部活動のデータが存在しなかった場合、内部の部活動オブジェクトが空の状態になり、プログラムを実行した際に処理が停止するエラーが発生しやすくなります。
具体的なプログラム例
ここでは、専用のデータ保持クラスを作成してDAOクラスからデータを返すJava言語による実装例を示します。プログラム内の表記において、太字や特殊な装飾は省いています。
Java
// 結合結果を受け取る専用のデータ保持クラス
public class StudentDepartmentDto {
private int studentId;
private String studentName;
private String departmentName;
public StudentDepartmentDto(int studentId, String studentName, String departmentName) {
this.studentId = studentId;
this.studentName = studentName;
this.departmentName = departmentName;
}
public int getStudentId() {
return studentId;
}
public String getStudentName() {
return studentName;
}
public String getDepartmentName() {
return departmentName;
}
}
Java
// データベースへのアクセスを担当するDAOクラス
public class StudentDao {
private Connection connection;
public StudentDao(Connection connection) {
this.connection = connection;
}
public List<StudentDepartmentDto> getStudentDepartmentList() {
List<StudentDepartmentDto> list = new ArrayList<>();
String sql = "SELECT s.id, s.name, d.name AS dept_name FROM students s INNER JOIN departments d ON s.department_id = d.id";
try (PreparedStatement statement = connection.prepareStatement(sql);
ResultSet resultSet = statement.executeQuery()) {
while (resultSet.next()) {
StudentDepartmentDto dto = new StudentDepartmentDto(
resultSet.getInt("id"),
resultSet.getString("name"),
resultSet.getString("dept_name")
);
list.add(dto);
}
} catch (SQLException e) {
e.printStackTrace();
}
return list;
}
}
まとめと学習のステップ
Joinを使用したSQLをDAOクラスに組み込む際は、結合結果を安全に受け取るためのデータ構造を明確に定義することが最も重要です。
初心者の皆様が、Joinを扱うDAOクラスの作成方法を体系的に習得するための論理的な学習ステップを以下に示します。
- ステップ1:1つの表からデータを取得する基本的なDAOクラスとデータ保持クラスの作成を経験する
- ステップ2:SQL文においてINNER JOINやLEFT JOINを使用し、意図通りの結合データが取得できるかを確認する
- ステップ3:結合結果の列名に対応する専用のデータ保持クラスを作成し、DAOクラスの戻り値として設定するプログラムを記述する
- ステップ4:結合元のデータが空の場合にプログラムが誤作動を起こさないよう、例外処理や条件分岐の記述方法を学ぶ
まずは小さな2つの表を結合する処理から開始し、データがどのようにクラスへ引き渡されるかを1行ずつ確認しながら学習を深めてみてください。
グループでは新人エンジニア研修のアシスタント講師を募集しています。
投稿者プロフィール

- 代表取締役
-
セイ・コンサルティング・グループ株式会社代表取締役。
岐阜県出身。
2000年創業、2004年会社設立。
IT企業向け人材育成研修歴業界歴20年以上。
すべての無駄を省いた費用対効果の高い「筋肉質」な研修を提供します!
この記事に間違い等ありましたらぜひお知らせください。
学生時代は趣味と実益を兼ねてリゾートバイトにいそしむ。長野県白馬村に始まり、志賀高原でのスキーインストラクター、沖縄石垣島、北海道トマム。高じてオーストラリアのゴールドコーストでツアーガイドなど。現在は野菜作りにはまっている。

