アグリゲート戦略
アグリゲート戦略は、任意のSELECT文からエンティティアグリゲートを構築する方法を定義します。リレーショナルなクエリ結果を階層構造のエンティティにマッピングするために、エンティティ同士の関連付け方法を指定する構造化されたアプローチを提供します。
アグリゲート戦略の定義
アグリゲート戦略は、インターフェースに @AggregateStrategy
アノテーションを付与することで表されます。このアノテーションは、クエリ結果からエンティティアグリゲートをどのように再構築するかを定義するために使用されます。
@AggregateStrategy(root = Department.class, tableAlias = "d")
interface DepartmentAggregateStrategy {
...
}
root
要素は、アグリゲートのルートとして機能するエンティティクラスを指定します。tableAlias
要素は、ルートエンティティクラスに対応するテーブルのエイリアスを指定します。 このエイリアスは、SELECT文でクエリの結果をエンティティプロパティに正しくマップするために使用する必要があります。
関連付けリンカーの定義
アグリゲート戦略には、@AssociationLinker
で注釈された BiFunction
型のフィールドが少なくとも1つ含まれている必要があります。BiFunction
は、2つのエンティティインスタンスを動的に関連付ける責任があります。
@AggregateStrategy(root = Department.class, tableAlias = "d")
interface DepartmentAggregateStrategy {
@AssociationLinker(propertyPath = "employees", tableAlias = "e")
BiFunction<Department, Employee, Department> employees =
(d, e) -> {
d.getEmployees().add(e);
e.setDepartment(d);
return d;
};
@AssociationLinker(propertyPath = "employees.address", tableAlias = "a")
BiFunction<Employee, Address, Employee> address =
(e, a) -> {
e.setAddress(a);
return e;
};
}
BiFunction
の最初と 3 番目の型パラメータはプロパティを所有するクラスを表し、2 番目の型パラメータはプロパティの型を表します。propertyPath
要素は、ルートエンティティクラスからドットで区切られたパスとしてターゲットプロパティの名前を指定します。tableAlias
要素は、BiFunction
の 2 番目の型パラメータとして使用されるエンティティクラスに対応するテーブルのエイリアスを指定します。 このエイリアスはSELECT文で使用する必要があります。
例
上記の DepartmentAggregateStrategy
は以下のエンティティ定義に基づいています。
@Entity(naming = NamingType.SNAKE_LOWER_CASE)
public class Department {
@Id Integer id;
String name;
@Association List<Employee> employees = new ArrayList<>();
// getter, setter
}
@Entity(naming = NamingType.SNAKE_LOWER_CASE)
public class Employee {
@Id Integer id;
String name;
Integer departmentId;
Integer addressId;
@Association Department department;
@Association Address address;
// getter, setter
}
@Entity(naming = NamingType.SNAKE_LOWER_CASE)
public class Address {
@Id Integer id;
String street;
// getter, setter
}
エンティティクラスでは、関連プロパティに @Association
を付与する必要があります。これらのプロパティは @AssociationLinker
を使用してリンクできます。
アグリゲート戦略の使用
DepartmentAggregateStrategy
は @Select
の aggregateStrategy
要素に指定することで使用されます。
@Dao
interface DepartmentDao {
@Select(aggregateStrategy = DepartmentAggregateStrategy.class)
Department selectById(Integer id);
}
selectById
メソッドでは、以下の SELECT ステートメントが必要になります。
select
d.id as d_id,
d.name as d_name,
a.id as a_id,
a.street as a_street,
e.id as e_id,
e.name as e_name,
e.department_id as e_department_id,
e.address_id as e_address_id
from
department d
left outer join
employee e on (d.id = e.department_id)
left outer join
address a on (e.address_id = a.id)
where
d.id = /* id */0
注釈
SELECTリストにはアグリゲートを形成するすべてのエンティティのIDを含める必要があります。
カラムエイリアスのルール
テーブルエイリアスは
DepartmentAggregateStrategy
で定義されているものと一致する必要があります。カラムのエイリアスは、テーブルのエイリアスにアンダースコア(
_
)を付けた形式で指定する必要があります。例えば、d.id
はd_id
、e.id
はe_id
としてエイリアスされます。
選択カラムリスト展開ディレクティブの使用
カラムリスト展開ディレクティブ を使用することで、上記のSELECT文をより簡潔に記述することができます。
select
/*%expand*/*
from
department d
left outer join
employee e on (d.id = e.department_id)
left outer join
address a on (e.address_id = a.id)
where
d.id = /* id */0
カラムリスト展開の仕組み
/*%expand */*
ディレクティブは、あらかじめ定義されたエイリアスルールを使用して列リストに自動的に展開します。デフォルトでは、すべてのテーブルのすべての列が結果セットに含まれます。
特定のテーブルのみを選択的に展開するには、テーブルエイリアスのカンマ区切りリストを渡します。
select
/*%expand "e, d" */*,
a.id as a_id,
a.street as a_street
from
department d
left outer join
employee e on (d.id = e.department_id)
left outer join
address a on (e.address_id = a.id)
where
d.id = /* id */0
ここでは、テーブルの
e
(employee
) とd
(department
) のカラムのみが展開されます。テーブル
a
(address
) の列は明示的に指定されています。