私は使用しています:
- 春 3.1
- 春のデータ JPA 1.1
- 休止状態 4.1
私は問題があります。標準の Spring Data JPA DAO があります。
public interface DnarDao extends JpaRepository<Dnar, Long> {
// insert Spring Data magic here!
}
Dnar
コードは次のとおりです。
@Entity
@Table(name="req_dnar", schema=SCHEMA)
@Inheritance(strategy=JOINED)
@DiscriminatorColumn(name="form_type", discriminatorType=STRING, length=64)
public abstract class Dnar {
@Id
@GeneratedValue(strategy=SEQUENCE, generator="dnar_gen_seq")
@SequenceGenerator(name="dnar_gen_seq", sequenceName="req_dnar_seq")
@Column(name=C_DNAR_ID, nullable=false)
private Long dnarId;
@Column(name="form_type", nullable=false, length=64)
@Enumerated(EnumType.STRING)
private FormType formType;
// remainder omitted
}
実装クラスの例:
@Entity
@Table(name="req_dnar_general_lv")
@DiscriminatorValue("GENERAL_LV")
public class GeneralLvDnar extends Dnar {
//remainder omitted
}
また、Hibernate 用の Spring 構成は次のとおりです。
<bean id="dataSource" class="oracle.jdbc.pool.OracleDataSource" destroy-method="close">
<property name="uRL" value="${JDBC_URL}"/>
<property name="user" value="${USER_ID}"/>
<property name="password" value="${PASSWORD}"/>
</bean>
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan">
<list><value>com/mycomp/domain</value></list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="ORACLE" />
<property name="generateDdl" value="true" />
<property name="showSql" value="true" />
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.id.new_generator_mappings">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<jpa:repositories base-package="com.mycomp.dao" />
<tx:annotation-driven />
ラウンド 1 - 問題
DAO のクライアントは次のDnarManagerImpl
クラスです。
@Transactional
@Override
public Dnar save(final Dnar dnar) {
Dnar managedDnar = dnarDao.save(dnar);
return managedDnar;
}
上記のコードは機能しますが、常にデータベースに新しいdnar
行が作成されます。Spring Data JPA コードをデバッグしましたが、正しく動作しているようです。たとえば、同じオブジェクトを 3 回保存すると、Hibernate の呼び出しは次のようになります。
getSession().persist(entity);
getSession().merge(entity);
getSession().merge(entity);
上記に対して Hibernate が出力する SQL は次のとおりです。
- に挿入...
- に挿入...
- に挿入...
ラウンド 2 - ハッキングの修正
少し実験した結果、 を使用して、このエンティティが存在することを現在のセッションに伝えることができることがわかりましたdnarDao.findOne(id);
。そして、これは私の問題を解決します:
@Transactional
@Override
public Dnar save(final Dnar dnar) {
// Hack to get the Dnar in the current persistence context
if (dnar.getDnarId() != null) {
dnarDao.findOne(dnar.getDnarId());
}
Dnar managedDnar = dnarDao.save(dnar);
return managedDnar;
}
ここでも、Hibernate セッションの呼び出しは次のとおりです。
getSession().persist(entity);
getSession().merge(entity);
getSession().merge(entity);
Hibernate が出力する SQL は正しいものになりました。
- に挿入...
- アップデート ...
- アップデート ...
質問
Hibernate docsによると、これはどのように機能するかmerge()
です:
- 永続化コンテキストに現在関連付けられている同じ識別子を持つマネージド インスタンスがある場合は、指定されたオブジェクトの状態をマネージド インスタンスにコピーします。
- 永続化コンテキストに現在関連付けられているマネージド インスタンスがない場合は、データベースからの読み込みを試みるか、新しいマネージド インスタンスを作成します。
- マネージド インスタンスが返される
- 指定されたインスタンスは永続コンテキストに関連付けられず、切り離されたままになり、通常は破棄されます
明らかに、私の例では、項目 2 は発生していません。Hibernate はデータベースからこのエンティティを読み込もうとしていません。Hibernateが選択を出力することはありません(私のハック修正では例外です)。すっごく....どこが間違っているのですか?Hibernate はドキュメントどおりに動作すると確信していますが、それは私が何かばかげたことをしただけです。