My開発メモ

LocalDateを使おうとすると、date型じゃだめ、timestampを使いなさいと言われた(spring boot)

『Spring徹底入門』の「第14章チュートリアル」を写経していて、エラーが出たので
そのメモ。

p642…p652 まで入力して、本に書かれてあるように Spring Boot の この
プロジェクトを再起動すると、以下のようなエラーが出た。

Schema-validation: wrong column type encountered in column [reserved_date] in table [reservable_room]; found [date (Types#DATE)], but expecting [timestamp (Types#TIMESTAMP)]

意味としては、
「テーブル[reservable_room] の中のカラム [reserved_date] のデータ型が悪い。
[timestamp] を期待していたのに、[date] だったよ。」
というような感じかな。

p652 の SQL文は、PostgreSQLのコマンドで実行しても、すんなり通ったので、
問題があるとするなら、Javaのコード。

ReservableRoom.java
package mrs.domain.model;

import java.io.Serializable;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.MapsId;

@Entity
public class ReservableRoom implements Serializable {
	// 複合主キー であることを表現するために、型をクラスとしている。
	// ReservableRoomId は roomId と reservedDate である。
	@EmbeddedId
	private ReservableRoomId reservableRoomId;
	
	// 多対1、
	// @JoinColumn -- 外部キーは、テーブルでは room_id になる。
	// @MapId -- 複合主キー ReservableRoomId のうち、参照するのは roomId である。
	@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 は省略
}

このコードの ER図 は、以下である。

+----------------------------+
| reservable_room            |
+----------------------------+
| (key) reserved_date : date |
| (key) roomId        : int  |
+----------------------------+

複合主キーになっているので、Javaコードでは、ReservedRoomIdクラスとして
表現している。

ReservedRoomIdクラスは以下である。

ReservableRoomId.java
package mrs.domain.model;

import java.io.Serializable;
import java.time.LocalDate;

import javax.persistence.Column;
import javax.persistence.Embeddable;

@Embeddable
public class ReservableRoomId implements Serializable {

	private Integer roomId;
	
	private LocalDate reservedDate;             // <== ここ
	
	public ReservableRoomId(Integer roomId, LocalDate reservedDate) {
		this.roomId = roomId;
		this.reservedDate = reservedDate;
	}
	
	public ReservableRoomId() {}

	@Override
	public int hashCode() {

           ( 省略 )
	}

	@Override
	public boolean equals(Object obj) {

           ( 省略 )
    }

    // getter, setter は省略
}

結論からいうと、上の

private LocalDate reservedDate;

@Column(columnDefinition = "DATE")
private LocalDate reservedDate;

とすると、エラーは消えた。

追記・原因がわかった

原因がわかった。p.650からの LocalDateConverter.java、LocalTimeConverter.java、LocalDateTimeConverter.java を書いたからだった ^^;

JPA2.1では LocalDate などに対応していないので、このコンバーターが必要なのだが、
今の僕の環境では必要ない。

つまり、LocalDate をわざわざ Timestamp に変換して読み込もうとしていたのである。

それを抑止する役目をしていたのが、columnDefinition = “DATE” だったというわけである。

参考

環境

カテゴリー: Java, memo

タグ: JPA, LocalDate, spring, spring-boot, timestamp

カウント: 204