複合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()に書き忘れると予想外の動作をしそうだね。ちょっと危険じゃない?
*1:http://d.hatena.ne.jp/koichik/20040611#1086962229
*2:http://www.hibernate.org/hib_docs/reference/en/html/mapping.html#mapping-declaration-compositeid
*3:http://javaboutique.internet.com/resources/hibernate/article.html
*4:http://www.jajakarta.org/commons/lang-1.0.1/ja/withPrimary/org/apache/commons/lang/builder/EqualsBuilder.html