S2JDBCでDialect指定忘れたばかりにID自動生成してもらえなくてハマるS2JDBCでID自動生成してもらえない

// ------------------
2008-12-30 12:52追記
id:taediumさんにご指摘いただきました。感謝です!
jdbc.diconだけ設定してs2jdbc.diconのdialect指定を忘れていたのが原因でした。
// ------------------


またライフハックネタでアプリを作り始める。
勉強を兼ねてScala+Lift・・・とか考えたけどまずScalaの習得からになるので今回はパス。
そこそこ小さなアプリなので、手軽に作れる素直にSAStruts + S2JDBC + HSQLDBで作り始める。

てか今のプロジェクトでSAStrutsが却下されてしまったので、SAStrutsでまともにモノを作るのは今回が初めてだったりしますが。


データ構造も単純だからデータインサートの部分くらいすぐできるだろうと思ってたら、さっそくエラー。メッセージが「エンティティ(Study)のIDプロパティ(id)の自動生成に失敗しました。」って。えー。

あれこれ試してみたものの、結局今日は原因を特定できずじまい。とりあえずSQLファイルにINSERT文を手書きして動くようにした。


// -------- 以下ソースの抜粋

テーブル定義

CREATE TABLE study (
   id integer generated by default as identity
  ,study_date DATE NOT NULL
  ,name VARCHAR(100) NOT NULL
  ,plan_minute INTEGER
  ,plan_quantity INTEGER
  ,result_minute INTEGER
  ,result_quantity INTEGER
  ,comment VARCHAR(255)
  ,parent_id INTEGER
);

エンティティ定義

@Entity
public class Study implements Serializable, Cloneable {
	
	private static final long serialVersionUID = -7448008552713640531L;

	@Id
	@GeneratedValue
	@Column(insertable=false) // Columnアノテーションなしでもエラー
	public Integer id;
	
	@Temporal(TemporalType.DATE)
	public Date studyDate;
	
	public String name;	
	public String comment;

	public int planMinute;
	public int planQuantity;
	
	public int resultMinute;
	public int resultQuantity;
	
	public Integer parentId;


	@Override
	public Study clone() {
		Study s = new Study();
		s.id = null;
		s.name = name;
		s.comment = comment;
		s.studyDate = (Date) studyDate.clone();
		s.planMinute = planMinute;
		s.planQuantity = planQuantity;
		s.resultMinute = resultMinute;
		s.resultQuantity = resultQuantity;
		s.parentId = parentId;
		return s;
	}
	
	@Override
	public String toString() {
             // デバッグ用途でオーバーライド
	}

結果のスタックトレースのメッセージは下記のもの

javax.servlet.ServletException: org.seasar.extension.jdbc.exception.IdGenerationFailedRuntimeException: [ESSR0738]エンティティ(Study)のIDプロパティ(id)の自動生成に失敗しました。
org.apache.struts.action.RequestProcessor.processException(RequestProcessor.java:535)
org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:433)
org.seasar.struts.action.S2RequestProcessor.process(S2RequestProcessor.java:125)
org.apache.struts.action.ActionServlet.process(ActionServlet.java:1196)
org.apache.struts.action.ActionServlet.doPost(ActionServlet.java:432)
javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
org.seasar.extension.filter.RequestDumpFilter.doFilter(RequestDumpFilter.java:127)
org.seasar.framework.container.hotdeploy.HotdeployFilter.doFilter(HotdeployFilter.java:75)
org.seasar.framework.container.filter.S2ContainerFilter.doFilter(S2ContainerFilter.java:79)
org.seasar.struts.filter.RoutingFilter.forward(RoutingFilter.java:204)
org.seasar.struts.filter.RoutingFilter.doFilter(RoutingFilter.java:137)
org.seasar.framework.container.hotdeploy.HotdeployFilter.doFilter(HotdeployFilter.java:63)
org.seasar.framework.container.filter.S2ContainerFilter.doFilter(S2ContainerFilter.java:79)
org.seasar.extension.filter.EncodingFilter.doFilter(EncodingFilter.java:69)

org.seasar.framework.exception.SSQLException: [ESSR0072]SQLで例外(SQL=[insert into STUDY (STUDY_DATE, NAME, COMMENT, PLAN_MINUTE, PLAN_QUANTITY, RESULT_MINUTE, RESULT_QUANTITY, PARENT_ID) values (?, ?, ?, ?, ?, ?, ?, ?)], Message=[-20], ErrorCode=IM001, SQLState={3})が発生しました


当面は下記のSQLで回避。IDカラムを明示的にインサート対象から除外。HSQLDBGUIマネージャで実行するとちゃんとインサート成功する。

INSERT INTO STUDY (
   study_date
  ,name
  ,plan_minute
  ,plan_quantity
  ,result_minute
  ,result_quantity
  ,comment
  ,parent_id)
VALUES (
   /*studyDate*/'2009-01-01'
  ,/*name*/'new study'
  ,/*planMinute*/5
  ,/*planQuantity*/10
  ,/*resultMinute*/15
  ,/*resultQuantity*/10
  ,/*comment*/'too difficult'
  ,/*parentId*/NULL
);


明日はもうちょっとだけ原因調べる。メッセージに従えば、ID自動生成の定義が悪いってことなんだろうけど。本家のチュートリアルとそう違ってないはずなんだけどなぁ。

// ------------------
2008-12-30 12:52追記その2
また「設定したつもり」という勘違いによる凡ミスで時間食った。
ノーモア勘違い。
// ------------------