🐙

JpaRepositoryのgetByIdはLazy Load

2021/12/03に公開

結論

JpaRepositoryのgetByIdは該当レコードが存在しない場合はEntityNotFoundExceptionを投げるみたい。これは永続プロバイダー次第だけど、ほとんどがそのようになっているそうな。
しかもLazy loadなので、getByIdを実行直後に例外が発生するのではなくて、戻り値を最初にアクセスしたときに例外を出すということだった。
javadocにちゃんとそう書いてあった。
自分で作ったメソッドfindByCodeなどはレコードがない場合にnullが返ってくるので注意が必要。

経緯

getByIdは該当するレコードがない場合はnullを返すものと勝手に思い込んでいた。

Optional<Circle> findById(long id) {
  CircleRecord record = CircleRepository.getById(id);
  return mapRecordToEntity(record);
}

Optional<Circle> mapRecordToEntity(CircleRecord record) {
  if (record == null) {
    return Optional.empty();
  }
  return new Optional.of(Circle(
    record.getId(),
    record.getName()
  ));
}

すると、record.getId()のところで、EntityNotFoundExceptionが出ることに気づいた。
id = 1でfindByIdを呼び出してデバッグすると、recordidは0だった。
getByIdのjavadocで調べてみると、最初にアクセスした時点でEntityNotFoundExceptionが発生するということだった。

レコードのエンティティは取得してすぐにドメインのエンティティに詰め替えるので、詰め替える場所をEntityNotFoundExceptionのtry catchで挟むだけでよかったので負担が少なかった。

Optional<Circle> mapRecordToEntity(CircleRecord record) {
  if (record == null) {
    return Optional.empty();
  }
  try {
    return new Optional.of(Circle(
      record.getId(),
      record.getName()
    ));
  } catch (EntityNotFoundException e) {
    return Optional.empty();
  }
}

Discussion