前回は、Hibernate EntitymanagerのテストケースをMySQL4.0で実行して結果を報告しました。その後、MySQL4.1/5.0でも同様にやってみましたが、エラーの状況は変わらず。
「SQL文法エラーが多い」ことを報告してましたが、SQLを抽出して、解決してみます。今日は、その報告です。
エラーを吐くSQLの抽出
テスト実行時、こんな感じに設定すれば、SQLだけが全部ログに吐き出されます。
./test/log4j.properties
log4j.appender.file=org.apache.log4j.FileAppender
log4j.appender.file.File=hibernate.log
log4j.appender.file.layout=org.apache.log4j.PatternLayout
log4j.appender.file.layout.ConversionPattern\
=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
log4j.rootLogger=warn, file
log4j.logger.org.hibernate.SQL=debug
テスト実行後のログを追ってみると、文法エラーになっているのは、次の4つ。
create table Race_Competitor (
Race_id integer not null,
competitors_id integer not null,
index integer not null,
primary key (Race_id, index)
,unique (competitors_id) )
create table Mail (
id bigint not null,
from varchar(255),
primary key (id))
create table Lock (
id integer not null auto_increment,
name varchar(255),
version integer,
primary key (id))
create table Workload (
id integer not null auto_increment,
name varchar(255),
load integer,
primary key (id))
テストケースの修正
一見なんのヘンテツもないSQLに見えますが、index、from、Lock、loadが予約語ですね。なんていじわるなテストケース(怒。
予約語は使わないように、各クラスをかきかえてみました。修正するファイルは、次の7つ。
org.hibernate.ejb.test.emops.Race
org.hibernate.ejb.test.lock.Lock
org.hibernate.ejb.test.lock.LockTest
org.hibernate.ejb.test.emops.Mail
org.hibernate.ejb.test.ops.Workload
org.hibernate.ejb.test.ops.GetLoadTest
org.hibernate.ejb.test.ops.mergeNewTest
修正方法は、プロパティ名を変えるか、アノテーションで違うカラム名にマップするかどちらか。
例えばLockの場合は、クラス名をかえてしまうか、
@Entity
@Table(name="Lock_")
public class Lock {
:
}
とかにすればOKです。
ここまで修正すると、SQLSyntaxエラーは消えて、テストカバレージは95.70%になります。MySQLは予約語に敏感なデータベースである。Entityクラスの命名には気を使わねば。という特徴が分かりました。これだけでも大きな収穫でした。
あとはシーケンスの問題
CascadeTestあたりで「シーケンスに対応していない」というエラーを吐いてしまいます。MySQLには、シーケンスオブジェクトの概念が存在しないので、どうしようもないのか。
これはEntityManagerではなくHibernate Coreの問題のようですが、Cascadeが使えないとなるとちょっと実用できないのかもしれません。
しかし、Hibernate Coreの内部では、シーケンスオブジェクトをテーブルを使ってエミュレートする機能があります(org.hibernate.idとorg.hibernate.dialectパッケージ)。
コレと、Cascadeの機能をうまく結びつける方法はないのでしょうか。これからもう少し、Hibernate Coreを掘り下げてみたいと思います。