複合Keyを利用したときのHibernateSystemException()

composite-idで複合Keyを設定してみた。

 
   
   
 


この時にExceptionが延々とでていた。

org.springframework.orm.hibernate.HibernateSystemException: identifier of an instance of hoge.entity.Users altered from hoge.entity.Users@146b6db[userId=3456789012,userName=ABCDEFGHIJKLMNOPQRST]
net.sf.hibernate.HibernateException: identifier of an instance of hoge.entity.Users altered from hoge.entity.Users@146b6db[userId=3456789012,userName=ABCDEFGHIJKLMNOPQRST]
 at net.sf.hibernate.impl.SessionImpl.checkId(SessionImpl.java:2642)
 at net.sf.hibernate.impl.SessionImpl.flushEntity(SessionImpl.java:2465)
 at net.sf.hibernate.impl.SessionImpl.flushEntities(SessionImpl.java:2458)
 at net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2260)
 at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2239)
 at org.springframework.orm.hibernate.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:214)
 at org.springframework.orm.hibernate.HibernateTemplate.execute(HibernateTemplate.java:244)
 at org.springframework.orm.hibernate.HibernateTemplate.executeFind(HibernateTemplate.java:263)
 at org.springframework.orm.hibernate.HibernateTemplate.find(HibernateTemplate.java:498)
 at hoge.dao.hibernate.UsersDaoImpl.getReport(UsersDaoImpl.java:20)
 at hoge.dao.hibernate.UsersDaoImpl.testGetReport(UsersDaoImpl.java:58)
 at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
 at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
 at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
 at java.lang.reflect.Method.invoke(Method.java:324)
 at junit.framework.TestCase.runTest(TestCase.java:154)
 at junit.framework.TestCase.runBare(TestCase.java:127)
 at junit.framework.TestResult$1.protect(TestResult.java:106)
 at junit.framework.TestResult.runProtected(TestResult.java:124)
 at junit.framework.TestResult.run(TestResult.java:109)
 at junit.framework.TestCase.run(TestCase.java:118)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:436)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:311)
 at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)

Eclipseでアプリそのものを動作させるとでないのだが、DbUnitからテストをするとgetHibernateTemplate().find〜でthrowされる。


原因はこういうことらしい*1

・equals(Object) および hashCode() をオーバーライドすること.
java.io.Serializable を implements すること.


なんのこっちゃと思って、本家*2をのぞく。

Your persistent class must override equals() and hashCode() to implement composite identifier equality. It must also implements Serializable.

・・・そのままだな。


ここ*3を参考に実装。
参考にしたもの

118    public boolean equals(Object other) {
119      if ( !(other instanceof Track) ) return false;
120      Track castOther = (Track) other;
121      return new EqualsBuilder( )
122        .append(this.getId( ), castOther.getId( ))
123        .isEquals( );
124    }
125
126    public int hashCode( ) {
127      return new HashCodeBuilder( )
128        .append(getId( ))
129        .toHashCode( );
130    }


インスタンスが異なっても、指すDBの列が同じ場合もあるので、entityのフィールドをすべて比較する必要があるわけか。


EqualsBuilder*4なんてはじめて使ったな。
いや、存在そのものを知らなかったのだが。


試してみたが、equals()の戻りがfalseになると上記のExcepton()がthrowされていた。ここが問題であったらしい。


これで解決・・・DbUnit経由でしか発生しなかった理由は不明だがOrz


しかしXMLでidのKeyを指定しても、equals()に書き忘れると予想外の動作をしそうだね。ちょっと危険じゃない?