Hibernate には、JPA マッピングを持つ次のクラスを持つ 2 つのクラスがあります。
package com.example.hibernate
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity
public class Foo {
private long id;
private Bar bar;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@ManyToOne(fetch = FetchType.LAZY)
public Bar getBar() {
return bar;
}
public void setBar(Bar bar) {
this.bar = bar;
}
}
package com.example.hibernate
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
public class Bar {
private long id;
private String title;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
データベースからセッション get を使用してクラス Foo からオブジェクトをロードすると、次のようになります。
Foo foo = (Foo)session.get(Foo.class, 1 /* または DB に存在するその他の ID*/); foo の Bar メンバーはプロキシ オブジェクト (この場合は javassist プロキシですが、使用するバイトコード プロバイダによっては cglib の場合もあります) であり、初期化されていません。次に、session.get を使用して、ロードしたばかりの Foo クラスのメンバーである Bar オブジェクトをフェッチすると (同じセッションにいます)、Hibernate は別の DB クエリを発行せず、セッション (第 1 レベル) キャッシュからオブジェクトをフェッチします。 . 問題は、これが初期化されていない Bar クラスへのプロキシであり、このオブジェクト getId() を呼び出そうとすると 0 が返され、getTitle() が null が返されることです。私たちの現在のソリューションはかなり醜く、get から返されたオブジェクトがプロキシかどうかをチェックします。コードは次のとおりです (一般的な DAO 実装から)。
@SuppressWarnings("unchecked")
@Override
@Transactional(readOnly = true)
public <T extends IEntity> T get(Class<T> clazz, Serializable primaryKey) throws DataAccessException {
T entity = (T) currentSession().get(clazz, primaryKey);
if (entity != null) {
if (LOG.isWarnEnabled()) {
LOG.warn("Object not found for class " + clazz.getName() + " with primary key " + primaryKey);
}
} else if (entity instanceof HibernateProxy){ // TODO: force initialization due to Hibernate bug
HibernateProxy proxy = (HibernateProxy)entity;
if (!Hibernate.isInitialized(proxy)) {
Hibernate.initialize(proxy);
}
entity = (T)proxy.getHibernateLazyInitializer().getImplementation();
}
return entity;
}
これを行うためのより良い方法はありますか、Hibernate フォーラムで解決策を見つけることができず、Hibernate の JIRA で問題を見つけることができませんでした。
注: foo.getBar() (プロキシを適切に初期化する) だけを使用して Bar クラス オブジェクトを取得することはできません。 class は、フェッチされたばかりの Foo オブジェクトの遅延メンバーでもあります。