Repositoryへ何を渡す?

メソッドによって異なる

Repositoryへ渡すものは、メソッドの目的によって異なります。取得には識別子や検索条件を渡し、保存には変更後のAggregate Rootを渡します。

findById()で取得する

取得したいAggregate Rootの識別子を渡します。

save()で保存する

変更後のAggregate Rootを渡します。

exists()で存在を確認する

確認したい対象の識別子や、業務上必要な条件を渡します。

delete()で削除する

設計に応じて、識別子またはAggregate Rootを渡します。

保存にはAggregate Rootを渡す

更新するときは、Repositoryへ変更項目を直接渡しません。取得したAggregate Rootのメソッドを呼び、業務ルールを確認して状態を変更してから、そのAggregate Rootをsave()へ渡します。

const recruitment = await repository.findById(recruitmentId);

if (!recruitment) {
  throw new Error("募集が見つかりません");
}

// Aggregate Rootが業務ルールを確認して状態を変更する
recruitment.requestParticipation({
  requesterId: participantId,
  now: requestedAt,
});

// 変更後のAggregate Rootを保存する
await repository.save(recruitment);

save(recruitmentId, participantId)のように変更内容だけを渡すと、Repositoryが業務上の判断まで担当することになります。Repositoryは保存を担当し、業務上の変更はAggregate Rootが担当します。

一部だけ変更する場合

開催場所だけを変更する場合でも、「募集」を表すAggregate Rootのメソッドを呼び、変更後のAggregate RootをRepositoryへ渡します。変更する項目の数ではなく、どのドメインモデルがその変更とルールに責任を持つかで判断するためです。

const recruitment = await repository.findById(recruitmentId);

// 「募集」が、開催場所を変更できる状態か確認して変更する
recruitment.changeLocation(newLocation);

// Repositoryには変更後の「募集」を渡す
await repository.save(recruitment);

Aggregate Rootを渡しても、DBのすべてのカラムを更新する必要はありません。どのカラムを更新するかはRepositoryの実装やORMが判断できるため、開催場所のカラムだけを更新することもできます。

一つの項目を変更するたびに大きなAggregate全体を読み込む必要があるなら、Aggregateの範囲が広すぎないかを見直します。業務ルールを守るために本当に必要な範囲だけを、一つのAggregateにします。