質問編集履歴
3
一応動作しましたが、理屈が理解できていません。
title
CHANGED
File without changes
|
body
CHANGED
@@ -207,3 +207,10 @@
|
|
207
207
|
```
|
208
208
|
「SQL Plusとプログラムで、見ているデータベースが異なるのではないか」とのご指摘の通りのようですが、理屈があまり理解できていません。
|
209
209
|
SQL Plusのconnectの書式か、spring.datasource.urlの書式のどちらかが誤っているのでしょうか?
|
210
|
+
|
211
|
+
### 2022/01/16追記
|
212
|
+
SQL PlusでテーブルをDROPして、アプリ側で「テーブル無し」のエラーとなることを確認しました。
|
213
|
+
SQL Plusでテーブルを作成する際に、わざとカラム属性を誤った属性にしたところ、エンティティの生成でエラーとなることを確認しました。
|
214
|
+
以上のことから、SQL Plusとプログラムで見ているデータベースは同じであると考えられます。
|
215
|
+
しかし、レコードのINSERTだけ、SQL Plusとプログラムで振る舞いが異なることを確認しています。
|
216
|
+
|
2
title
CHANGED
File without changes
|
body
CHANGED
@@ -1,198 +1,209 @@
|
|
1
|
-
### Spring Data JPA のクエリメソッド名を使用した検索を行うと、検索結果が0件になる
|
2
|
-
|
3
|
-
チュートリアルを基に、Springを学習中です。
|
4
|
-
チュートリアルではPostgreSQLを使用していましたが、手持ちの環境の都合上、Oracle 18c XEを使用しました。
|
5
|
-
「メソッド名からクエリを生成する方法」の所で、意図した検索結果にならず、つまづいています。
|
6
|
-
具体的には、生成されたクエリを実行すると、SQL Plusだと検索されますが、プログラムからは検索結果が0件になってしまいます。
|
7
|
-
|
8
|
-
### 発生している問題・エラーメッセージ
|
9
|
-
ログから、以下のクエリが生成されていることを確認しました。
|
10
|
-
バインドされた値も確認しました。
|
11
|
-
```log
|
12
|
-
2022-01-07 10:50:52.422 DEBUG 16596 --- [nio-8080-exec-1] org.hibernate.SQL :
|
13
|
-
select
|
14
|
-
reservable0_.reserved_date as reserved_date1_1_,
|
15
|
-
reservable0_.room_id as room_id2_1_
|
16
|
-
from
|
17
|
-
reservable_room reservable0_
|
18
|
-
where
|
19
|
-
reservable0_.reserved_date=?
|
20
|
-
order by
|
21
|
-
reservable0_.room_id asc
|
22
|
-
Hibernate:
|
23
|
-
select
|
24
|
-
reservable0_.reserved_date as reserved_date1_1_,
|
25
|
-
reservable0_.room_id as room_id2_1_
|
26
|
-
from
|
27
|
-
reservable_room reservable0_
|
28
|
-
where
|
29
|
-
reservable0_.reserved_date=?
|
30
|
-
order by
|
31
|
-
reservable0_.room_id asc
|
32
|
-
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]
|
33
|
-
```
|
34
|
-
|
35
|
-
SQL Plusの実行結果は以下の通りです(一部省略)。
|
36
|
-
```sql
|
37
|
-
SQL> select
|
38
|
-
2 reservable0_.reserved_date as reserved_date1_1_,
|
39
|
-
3 reservable0_.room_id as room_id2_1_
|
40
|
-
4 from
|
41
|
-
5 reservable_room reservable0_
|
42
|
-
6 where
|
43
|
-
7 reservable0_.reserved_date='2022-01-07'
|
44
|
-
8 order by
|
45
|
-
9 reservable0_.room_id asc;
|
46
|
-
|
47
|
-
RESERVED_DATE1_1_
|
48
|
-
--------------------
|
49
|
-
ROOM_ID2_1_
|
50
|
-
-----------
|
51
|
-
2022-01-07
|
52
|
-
1
|
53
|
-
|
54
|
-
2022-01-07
|
55
|
-
2
|
56
|
-
|
57
|
-
2022-01-07
|
58
|
-
3
|
59
|
-
(以降省略)
|
60
|
-
|
61
|
-
7行が選択されました。
|
62
|
-
```
|
63
|
-
これが、プログラムの実行結果を確認すると、検索結果が0件になります。
|
64
|
-
|
65
|
-
### 該当のソースコード
|
66
|
-
検索の実行個所は以下の通りです(一部抜粋)。
|
67
|
-
```java
|
68
|
-
@RequestMapping(method = RequestMethod.GET)
|
69
|
-
String listRooms(Model model) {
|
70
|
-
String date = LocalDate.now().toString();
|
71
|
-
|
72
|
-
List<ReservableRoom> rooms = roomService.findReservableRooms(date);
|
73
|
-
// デバッグ用
|
74
|
-
System.out.println("rooms count:" + rooms.size()); //ここが0件になる
|
75
|
-
|
76
|
-
model.addAttribute("date", date);
|
77
|
-
model.addAttribute("rooms", rooms);
|
78
|
-
return "room/listRooms";
|
79
|
-
}
|
80
|
-
```
|
81
|
-
検索メソッドのソースは以下の通りです(エンティティのゲッター/セッターは省略しています)。
|
82
|
-
```java
|
83
|
-
@Service
|
84
|
-
@Transactional
|
85
|
-
public class RoomService {
|
86
|
-
|
87
|
-
@Autowired
|
88
|
-
ReservableRoomRepository reservableRoomRepository;
|
89
|
-
|
90
|
-
public List<ReservableRoom> findReservableRooms(String date) {
|
91
|
-
return reservableRoomRepository.findByReservableRoomId_reservedDateOrderByReservableRoomId_roomIdAsc(date);
|
92
|
-
}
|
93
|
-
}
|
94
|
-
```
|
95
|
-
```java
|
96
|
-
public interface ReservableRoomRepository extends JpaRepository<ReservableRoom, ReservableRoomId> {
|
97
|
-
List<ReservableRoom> findByReservableRoomId_reservedDateOrderByReservableRoomId_roomIdAsc(String reservedDate);
|
98
|
-
}
|
99
|
-
```
|
100
|
-
```java
|
101
|
-
@Entity
|
102
|
-
public class ReservableRoom implements Serializable {
|
103
|
-
@EmbeddedId
|
104
|
-
private ReservableRoomId reservableRoomId;
|
105
|
-
|
106
|
-
@ManyToOne
|
107
|
-
@JoinColumn(name = "room_id", insertable = false, updatable = false)
|
108
|
-
@MapsId("roomId")
|
109
|
-
private MeetingRoom meetingRoom;
|
110
|
-
|
111
|
-
public ReservableRoom(ReservableRoomId reservableRoomId) {
|
112
|
-
this.reservableRoomId = reservableRoomId;
|
113
|
-
}
|
114
|
-
|
115
|
-
public ReservableRoom() {
|
116
|
-
}
|
117
|
-
//getter/setterは省略
|
118
|
-
}
|
119
|
-
```
|
120
|
-
```java
|
121
|
-
@Embeddable
|
122
|
-
public class ReservableRoomId implements Serializable {
|
123
|
-
private Integer roomId;
|
124
|
-
private String reservedDate;
|
125
|
-
|
126
|
-
public ReservableRoomId(Integer roomId, String reservedDate) {
|
127
|
-
this.roomId = roomId;
|
128
|
-
this.reservedDate = reservedDate;
|
129
|
-
}
|
130
|
-
|
131
|
-
public ReservableRoomId() {
|
132
|
-
}
|
133
|
-
|
134
|
-
@Override
|
135
|
-
public int hashCode() {
|
136
|
-
final int prime = 31;
|
137
|
-
int result = 1;
|
138
|
-
result = prime * result + ((reservedDate == null) ? 0 : reservedDate.hashCode());
|
139
|
-
result = prime * result + ((roomId == null) ? 0 : roomId.hashCode());
|
140
|
-
return result;
|
141
|
-
}
|
142
|
-
|
143
|
-
@Override
|
144
|
-
public boolean equals(Object obj) {
|
145
|
-
if(this == obj) return true;
|
146
|
-
if(obj == null) return false;
|
147
|
-
if(getClass() != obj.getClass()) return false;
|
148
|
-
ReservableRoomId other = (ReservableRoomId) obj;
|
149
|
-
if(reservedDate == null) {
|
150
|
-
if(other.reservedDate != null) return false;
|
151
|
-
}else if(!reservedDate.equals(other.reservedDate))
|
152
|
-
return false;
|
153
|
-
if(roomId == null) {
|
154
|
-
if(other.roomId != null) return false;
|
155
|
-
}else if(!roomId.equals(other.roomId))
|
156
|
-
return false;
|
157
|
-
return true;
|
158
|
-
}
|
159
|
-
//getter/setterは省略
|
160
|
-
}
|
161
|
-
```
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
### 試したこと
|
166
|
-
- ログの確認
|
167
|
-
- SQL Plusでの動作検証
|
168
|
-
- デバッグ出力の追加
|
169
|
-
- PostgreSQLとOracleの非互換調査
|
170
|
-
- チュートリアルとのソースの突合せ
|
171
|
-
- [Spring Data JPA リファレンス](https://spring.pleiades.io/spring-data/jpa/docs/current/reference/html/#reference)の確認
|
172
|
-
- Googleで類似事例の確認
|
173
|
-
|
174
|
-
### 補足情報(FW/ツールのバージョンなど)
|
175
|
-
|
176
|
-
- Spring Boot 2.6.2
|
177
|
-
- Java 11
|
178
|
-
- Oracle 18c XE
|
179
|
-
|
180
|
-
### 2022/01/10追記
|
181
|
-
「SQL Plusとプログラム
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
```
|
187
|
-
|
188
|
-
spring.datasource.
|
189
|
-
spring.datasource.
|
190
|
-
spring.datasource.
|
191
|
-
spring.
|
192
|
-
spring.jpa.
|
193
|
-
spring.jpa.
|
194
|
-
spring.jpa.
|
195
|
-
spring.
|
196
|
-
|
197
|
-
logging.level.org.hibernate.
|
198
|
-
|
1
|
+
### Spring Data JPA のクエリメソッド名を使用した検索を行うと、検索結果が0件になる
|
2
|
+
|
3
|
+
チュートリアルを基に、Springを学習中です。
|
4
|
+
チュートリアルではPostgreSQLを使用していましたが、手持ちの環境の都合上、Oracle 18c XEを使用しました。
|
5
|
+
「メソッド名からクエリを生成する方法」の所で、意図した検索結果にならず、つまづいています。
|
6
|
+
具体的には、生成されたクエリを実行すると、SQL Plusだと検索されますが、プログラムからは検索結果が0件になってしまいます。
|
7
|
+
|
8
|
+
### 発生している問題・エラーメッセージ
|
9
|
+
ログから、以下のクエリが生成されていることを確認しました。
|
10
|
+
バインドされた値も確認しました。
|
11
|
+
```log
|
12
|
+
2022-01-07 10:50:52.422 DEBUG 16596 --- [nio-8080-exec-1] org.hibernate.SQL :
|
13
|
+
select
|
14
|
+
reservable0_.reserved_date as reserved_date1_1_,
|
15
|
+
reservable0_.room_id as room_id2_1_
|
16
|
+
from
|
17
|
+
reservable_room reservable0_
|
18
|
+
where
|
19
|
+
reservable0_.reserved_date=?
|
20
|
+
order by
|
21
|
+
reservable0_.room_id asc
|
22
|
+
Hibernate:
|
23
|
+
select
|
24
|
+
reservable0_.reserved_date as reserved_date1_1_,
|
25
|
+
reservable0_.room_id as room_id2_1_
|
26
|
+
from
|
27
|
+
reservable_room reservable0_
|
28
|
+
where
|
29
|
+
reservable0_.reserved_date=?
|
30
|
+
order by
|
31
|
+
reservable0_.room_id asc
|
32
|
+
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]
|
33
|
+
```
|
34
|
+
|
35
|
+
SQL Plusの実行結果は以下の通りです(一部省略)。
|
36
|
+
```sql
|
37
|
+
SQL> select
|
38
|
+
2 reservable0_.reserved_date as reserved_date1_1_,
|
39
|
+
3 reservable0_.room_id as room_id2_1_
|
40
|
+
4 from
|
41
|
+
5 reservable_room reservable0_
|
42
|
+
6 where
|
43
|
+
7 reservable0_.reserved_date='2022-01-07'
|
44
|
+
8 order by
|
45
|
+
9 reservable0_.room_id asc;
|
46
|
+
|
47
|
+
RESERVED_DATE1_1_
|
48
|
+
--------------------
|
49
|
+
ROOM_ID2_1_
|
50
|
+
-----------
|
51
|
+
2022-01-07
|
52
|
+
1
|
53
|
+
|
54
|
+
2022-01-07
|
55
|
+
2
|
56
|
+
|
57
|
+
2022-01-07
|
58
|
+
3
|
59
|
+
(以降省略)
|
60
|
+
|
61
|
+
7行が選択されました。
|
62
|
+
```
|
63
|
+
これが、プログラムの実行結果を確認すると、検索結果が0件になります。
|
64
|
+
|
65
|
+
### 該当のソースコード
|
66
|
+
検索の実行個所は以下の通りです(一部抜粋)。
|
67
|
+
```java
|
68
|
+
@RequestMapping(method = RequestMethod.GET)
|
69
|
+
String listRooms(Model model) {
|
70
|
+
String date = LocalDate.now().toString();
|
71
|
+
|
72
|
+
List<ReservableRoom> rooms = roomService.findReservableRooms(date);
|
73
|
+
// デバッグ用
|
74
|
+
System.out.println("rooms count:" + rooms.size()); //ここが0件になる
|
75
|
+
|
76
|
+
model.addAttribute("date", date);
|
77
|
+
model.addAttribute("rooms", rooms);
|
78
|
+
return "room/listRooms";
|
79
|
+
}
|
80
|
+
```
|
81
|
+
検索メソッドのソースは以下の通りです(エンティティのゲッター/セッターは省略しています)。
|
82
|
+
```java
|
83
|
+
@Service
|
84
|
+
@Transactional
|
85
|
+
public class RoomService {
|
86
|
+
|
87
|
+
@Autowired
|
88
|
+
ReservableRoomRepository reservableRoomRepository;
|
89
|
+
|
90
|
+
public List<ReservableRoom> findReservableRooms(String date) {
|
91
|
+
return reservableRoomRepository.findByReservableRoomId_reservedDateOrderByReservableRoomId_roomIdAsc(date);
|
92
|
+
}
|
93
|
+
}
|
94
|
+
```
|
95
|
+
```java
|
96
|
+
public interface ReservableRoomRepository extends JpaRepository<ReservableRoom, ReservableRoomId> {
|
97
|
+
List<ReservableRoom> findByReservableRoomId_reservedDateOrderByReservableRoomId_roomIdAsc(String reservedDate);
|
98
|
+
}
|
99
|
+
```
|
100
|
+
```java
|
101
|
+
@Entity
|
102
|
+
public class ReservableRoom implements Serializable {
|
103
|
+
@EmbeddedId
|
104
|
+
private ReservableRoomId reservableRoomId;
|
105
|
+
|
106
|
+
@ManyToOne
|
107
|
+
@JoinColumn(name = "room_id", insertable = false, updatable = false)
|
108
|
+
@MapsId("roomId")
|
109
|
+
private MeetingRoom meetingRoom;
|
110
|
+
|
111
|
+
public ReservableRoom(ReservableRoomId reservableRoomId) {
|
112
|
+
this.reservableRoomId = reservableRoomId;
|
113
|
+
}
|
114
|
+
|
115
|
+
public ReservableRoom() {
|
116
|
+
}
|
117
|
+
//getter/setterは省略
|
118
|
+
}
|
119
|
+
```
|
120
|
+
```java
|
121
|
+
@Embeddable
|
122
|
+
public class ReservableRoomId implements Serializable {
|
123
|
+
private Integer roomId;
|
124
|
+
private String reservedDate;
|
125
|
+
|
126
|
+
public ReservableRoomId(Integer roomId, String reservedDate) {
|
127
|
+
this.roomId = roomId;
|
128
|
+
this.reservedDate = reservedDate;
|
129
|
+
}
|
130
|
+
|
131
|
+
public ReservableRoomId() {
|
132
|
+
}
|
133
|
+
|
134
|
+
@Override
|
135
|
+
public int hashCode() {
|
136
|
+
final int prime = 31;
|
137
|
+
int result = 1;
|
138
|
+
result = prime * result + ((reservedDate == null) ? 0 : reservedDate.hashCode());
|
139
|
+
result = prime * result + ((roomId == null) ? 0 : roomId.hashCode());
|
140
|
+
return result;
|
141
|
+
}
|
142
|
+
|
143
|
+
@Override
|
144
|
+
public boolean equals(Object obj) {
|
145
|
+
if(this == obj) return true;
|
146
|
+
if(obj == null) return false;
|
147
|
+
if(getClass() != obj.getClass()) return false;
|
148
|
+
ReservableRoomId other = (ReservableRoomId) obj;
|
149
|
+
if(reservedDate == null) {
|
150
|
+
if(other.reservedDate != null) return false;
|
151
|
+
}else if(!reservedDate.equals(other.reservedDate))
|
152
|
+
return false;
|
153
|
+
if(roomId == null) {
|
154
|
+
if(other.roomId != null) return false;
|
155
|
+
}else if(!roomId.equals(other.roomId))
|
156
|
+
return false;
|
157
|
+
return true;
|
158
|
+
}
|
159
|
+
//getter/setterは省略
|
160
|
+
}
|
161
|
+
```
|
162
|
+
|
163
|
+
|
164
|
+
|
165
|
+
### 試したこと
|
166
|
+
- ログの確認
|
167
|
+
- SQL Plusでの動作検証
|
168
|
+
- デバッグ出力の追加
|
169
|
+
- PostgreSQLとOracleの非互換調査
|
170
|
+
- チュートリアルとのソースの突合せ
|
171
|
+
- [Spring Data JPA リファレンス](https://spring.pleiades.io/spring-data/jpa/docs/current/reference/html/#reference)の確認
|
172
|
+
- Googleで類似事例の確認
|
173
|
+
|
174
|
+
### 補足情報(FW/ツールのバージョンなど)
|
175
|
+
|
176
|
+
- Spring Boot 2.6.2
|
177
|
+
- Java 11
|
178
|
+
- Oracle 18c XE
|
179
|
+
|
180
|
+
### 2022/01/10追記
|
181
|
+
「SQL Plusとプログラムで、見ているデータベースが異なるのではないか」とのご指摘をいただきました。
|
182
|
+
同じデータベースを参照している認識です。
|
183
|
+
以下に、SQL Plusのログインとapplication.propertiesを掲載します。
|
184
|
+
```sql
|
185
|
+
connect xxxx/xxxx@//localhost:1521/XEPDB1
|
186
|
+
```
|
187
|
+
```properties
|
188
|
+
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
|
189
|
+
spring.datasource.url=jdbc:oracle:thin:@//localhost:1521/XEPDB1
|
190
|
+
spring.datasource.username=xxxx
|
191
|
+
spring.datasource.password=xxxx
|
192
|
+
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
|
193
|
+
spring.jpa.show-sql=true
|
194
|
+
spring.jpa.hibernate.ddl-auto=validate
|
195
|
+
spring.jpa.properties.hibernate.format_sql=true
|
196
|
+
spring.sql.init.encoding=UTF-8
|
197
|
+
logging.level.org.hibernate.SQL=DEBUG
|
198
|
+
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
|
199
|
+
```
|
200
|
+
|
201
|
+
|
202
|
+
### 2022/01/13追記
|
203
|
+
application.propertiesに以下を追記し、schema.sqlとdata.sqlからデータベースを作成してみたところ、正常に動作しました。
|
204
|
+
```properties
|
205
|
+
spring.sql.init.mode=always
|
206
|
+
spring.sql.init.schema-locations=classpath:schema.sql
|
207
|
+
```
|
208
|
+
「SQL Plusとプログラムで、見ているデータベースが異なるのではないか」とのご指摘の通りのようですが、理屈があまり理解できていません。
|
209
|
+
SQL Plusのconnectの書式か、spring.datasource.urlの書式のどちらかが誤っているのでしょうか?
|
1
「SQL Plusとプログラムとで別のデータベースを見ているのではないか」とのご指摘について、ログイン方法とapplication.propertiesを追記しました。
title
CHANGED
File without changes
|
body
CHANGED
@@ -175,4 +175,24 @@
|
|
175
175
|
|
176
176
|
- Spring Boot 2.6.2
|
177
177
|
- Java 11
|
178
|
-
- Oracle 18c XE
|
178
|
+
- Oracle 18c XE
|
179
|
+
|
180
|
+
### 2022/01/10追記
|
181
|
+
「SQL Plusとプログラムとで別のデータベースを見ているのではないか」とのご指摘を受けました。
|
182
|
+
以下にSQL Plusのログイン方法及びapplication.propertiesを掲載します。同一のデータベースの認識です。
|
183
|
+
```sql
|
184
|
+
connect xxxx/xxxx@//localhost:1521/XEPDB1
|
185
|
+
```
|
186
|
+
```properties
|
187
|
+
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
|
188
|
+
spring.datasource.url=jdbc:oracle:thin:@//localhost:1521/XEPDB1
|
189
|
+
spring.datasource.username=xxxx
|
190
|
+
spring.datasource.password=xxxx
|
191
|
+
spring.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
|
192
|
+
spring.jpa.show-sql=true
|
193
|
+
spring.jpa.hibernate.ddl-auto=validate
|
194
|
+
spring.jpa.properties.hibernate.format_sql=true
|
195
|
+
spring.sql.init.encoding=UTF-8
|
196
|
+
logging.level.org.hibernate.SQL=DEBUG
|
197
|
+
logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE
|
198
|
+
```
|