Spring Data JPA のクエリメソッド名を使用した検索を行うと、検索結果が0件になる
チュートリアルを基に、Springを学習中です。
チュートリアルではPostgreSQLを使用していましたが、手持ちの環境の都合上、Oracle 18c XEを使用しました。
「メソッド名からクエリを生成する方法」の所で、意図した検索結果にならず、つまづいています。
具体的には、生成されたクエリを実行すると、SQL Plusだと検索されますが、プログラムからは検索結果が0件になってしまいます。
発生している問題・エラーメッセージ
ログから、以下のクエリが生成されていることを確認しました。
バインドされた値も確認しました。
log
2022-01-07 10:50:52.422 DEBUG 16596 --- [nio-8080-exec-1] org.hibernate.SQL : select reservable0_.reserved_date as reserved_date1_1_, reservable0_.room_id as room_id2_1_ from reservable_room reservable0_ where reservable0_.reserved_date=? order by reservable0_.room_id asc Hibernate: select reservable0_.reserved_date as reserved_date1_1_, reservable0_.room_id as room_id2_1_ from reservable_room reservable0_ where reservable0_.reserved_date=? order by reservable0_.room_id asc 2022-01-07 10:50:52.423 TRACE 16596 --- [nio-8080-exec-1] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [2022-01-07]
SQL Plusの実行結果は以下の通りです(一部省略)。
sql
SQL> select 2 reservable0_.reserved_date as reserved_date1_1_, 3 reservable0_.room_id as room_id2_1_ 4 from 5 reservable_room reservable0_ 6 where 7 reservable0_.reserved_date='2022-01-07' 8 order by 9 reservable0_.room_id asc; RESERVED_DATE1_1_ -------------------- ROOM_ID2_1_ ----------- 2022-01-07 1 2022-01-07 2 2022-01-07 3 (以降省略) 7行が選択されました。
これが、プログラムの実行結果を確認すると、検索結果が0件になります。
該当のソースコード
検索の実行個所は以下の通りです(一部抜粋)。
java
@RequestMapping(method = RequestMethod.GET) String listRooms(Model model) { String date = LocalDate.now().toString(); List<ReservableRoom> rooms = roomService.findReservableRooms(date); // デバッグ用 System.out.println("rooms count:" + rooms.size()); //ここが0件になる model.addAttribute("date", date); model.addAttribute("rooms", rooms); return "room/listRooms"; }
検索メソッドのソースは以下の通りです(エンティティのゲッター/セッターは省略しています)。
java
@Service @Transactional public class RoomService { @Autowired ReservableRoomRepository reservableRoomRepository; public List<ReservableRoom> findReservableRooms(String date) { return reservableRoomRepository.findByReservableRoomId_reservedDateOrderByReservableRoomId_roomIdAsc(date); } }
java
public interface ReservableRoomRepository extends JpaRepository<ReservableRoom, ReservableRoomId> { List<ReservableRoom> findByReservableRoomId_reservedDateOrderByReservableRoomId_roomIdAsc(String reservedDate); }
java
@Entity public class ReservableRoom implements Serializable { @EmbeddedId private ReservableRoomId reservableRoomId; @ManyToOne @JoinColumn(name = "room_id", insertable = false, updatable = false) @MapsId("roomId") private MeetingRoom meetingRoom; public ReservableRoom(ReservableRoomId reservableRoomId) { this.reservableRoomId = reservableRoomId; } public ReservableRoom() { } //getter/setterは省略 }
java
@Embeddable public class ReservableRoomId implements Serializable { private Integer roomId; private String reservedDate; public ReservableRoomId(Integer roomId, String reservedDate) { this.roomId = roomId; this.reservedDate = reservedDate; } public ReservableRoomId() { } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((reservedDate == null) ? 0 : reservedDate.hashCode()); result = prime * result + ((roomId == null) ? 0 : roomId.hashCode()); return result; } @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null) return false; if(getClass() != obj.getClass()) return false; ReservableRoomId other = (ReservableRoomId) obj; if(reservedDate == null) { if(other.reservedDate != null) return false; }else if(!reservedDate.equals(other.reservedDate)) return false; if(roomId == null) { if(other.roomId != null) return false; }else if(!roomId.equals(other.roomId)) return false; return true; } //getter/setterは省略 }
試したこと
- ログの確認
- SQL Plusでの動作検証
- デバッグ出力の追加
- PostgreSQLとOracleの非互換調査
- チュートリアルとのソースの突合せ
- Spring Data JPA リファレンスの確認
- Googleで類似事例の確認
補足情報(FW/ツールのバージョンなど)
- Spring Boot 2.6.2
- Java 11
- Oracle 18c XE
2022/01/10追記
「SQL Plusとプログラムで、見ているデータベースが異なるのではないか」とのご指摘をいただきました。
同じデータベースを参照している認識です。
以下に、SQL Plusのログインとapplication.propertiesを掲載します。
sql
connect xxxx/xxxx@//localhost:1521/XEPDB1
properties
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver spring.datasource.url=jdbc:oracle:thin:@//localhost:1521/XEPDB1 spring.datasource.username=xxxx spring.datasource.password=xxxx spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect spring.jpa.show-sql=true spring.jpa.hibernate.ddl-auto=validate spring.jpa.properties.hibernate.format_sql=true spring.sql.init.encoding=UTF-8 logging.level.org.hibernate.SQL=DEBUG logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
2022/01/13追記
application.propertiesに以下を追記し、schema.sqlとdata.sqlからデータベースを作成してみたところ、正常に動作しました。
properties
spring.sql.init.mode=always spring.sql.init.schema-locations=classpath:schema.sql
「SQL Plusとプログラムで、見ているデータベースが異なるのではないか」とのご指摘の通りのようですが、理屈があまり理解できていません。
SQL Plusのconnectの書式か、spring.datasource.urlの書式のどちらかが誤っているのでしょうか?
2022/01/16追記
SQL PlusでテーブルをDROPして、アプリ側で「テーブル無し」のエラーとなることを確認しました。
SQL Plusでテーブルを作成する際に、わざとカラム属性を誤った属性にしたところ、エンティティの生成でエラーとなることを確認しました。
以上のことから、SQL Plusとプログラムで見ているデータベースは同じであると考えられます。
しかし、レコードのINSERTだけ、SQL Plusとプログラムで振る舞いが異なることを確認しています。
まだ回答がついていません
会員登録して回答してみよう