Apache DERBY 組み込みデータベースに接続する Java の SWING アプリケーションで JPA を使用しています。私は Netbeans を IDE として使用し、「おそらく」役立つテンプレートを多数使用しています。私の問題は簡単ですが、説明するのは難しいので、関連するコードをここに貼り付けて、一番下で説明しようとします。
@Entity
public class AnioLectivo implements Serializable, Comparable
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
@OneToMany(mappedBy = "anioLectivo", cascade=CascadeType.ALL)
private List<Compensatorio> compensatorios;
...
}
@Entity
public class Compensatorio implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
...
@ManyToOne
private AnioLectivo anioLectivo;
...
}
これらの 2 つは、永続化したいエンティティです。
public class AnioLectivoJpaController
{
public void edit(AnioLectivo anioLectivo) throws NonexistentEntityException,
Exception
{
EntityManager em = null;
try {
em = getEntityManager();
em.getTransaction().begin();
AnioLectivo persistentAnioLectivo = em.find(AnioLectivo.class,
anioLectivo.getId());
...
List<Compensatorio> compensatoriosOld =
persistentAnioLectivo.getCompensatorios();
List<Compensatorio> compensatoriosNew = anioLectivo.getCompensatorios();
...
List<Compensatorio> attachedCompensatoriosNew = new ArrayList<Compensatorio>();
for (Compensatorio compensatoriosNewCompensatorioToAttach : compensatoriosNew) {
compensatoriosNewCompensatorioToAttach =
em.getReference(compensatoriosNewCompensatorioToAttach.getClass(),
compensatoriosNewCompensatorioToAttach.getId());
attachedCompensatoriosNew.add(compensatoriosNewCompensatorioToAttach);
}
compensatoriosNew = attachedCompensatoriosNew;
anioLectivo.setCompensatorios(compensatoriosNew);
...
}
これは、以前に貼り付けたエンティティ AnioLectivo の注釈を使用して netbeans が生成するクラスです。ご覧のとおり、問題がここにあることが netbeans のデバッグ ツールのおかげでわかっているので、単純にするために問題に関連するコードのみを貼り付けました。ここで、何が起こるかを正確に説明しようと思います。
プログラムの一部で AnioLectivo のインスタンスを作成し、それらを永続化します。次に、別の部分で、AnioLectivo のインスタンスで Compensatorio のインスタンスを作成し、Compensatorio のリストに追加する必要があります。ここで、この変更を保存したいと思います。これは、クラス AnioLectivoJpaController の edit メソッドを使用して行われたと想定していますが、次のエラーが見つかりました。
java.lang.IllegalArgumentException: An instance of a null PK has been incorrectly provided for this find operation.
at oracle.toplink.essentials.internal.ejb.cmp3.base.EntityManagerImpl.findInternal(EntityManagerImpl.java:309)
at oracle.toplink.essentials.internal.ejb.cmp3.EntityManagerImpl.getReference(EntityManagerImpl.java:176)
at org.sigeb.local.service.dao.jpa.AnioLectivoJpaController.edit(AnioLectivoJpaController.java:113)
at org.sigeb.local.views.datosIniciales.AdministrarCursosPopUp.guardarCambios(AdministrarCursosPopUp.java:574)
at org.sigeb.local.views.datosIniciales.AdministrarCursosPopUp.jBGuardarCambiosActionPerformed(AdministrarCursosPopUp.java:394)
at org.sigeb.local.views.datosIniciales.AdministrarCursosPopUp.access$1000(AdministrarCursosPopUp.java:44)
at org.sigeb.local.views.datosIniciales.AdministrarCursosPopUp$11.actionPerformed(AdministrarCursosPopUp.java:204)
at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1995)
at javax.swing.AbstractButton$Handler.actionPerformed(AbstractButton.java:2318)
...
私が見ているように、問題は AnioLectivoJpaController の edit メソッドの次のコード行で発生します。
em.getReference(compensatoriosNewCompensatorioToAttach.getClass(),
compensatoriosNewCompensatorioToAttach.getId());
なんで?エンティティが表示されている場合、すべてのエンティティの ID が永続化ユニットによって生成されるように定義しましたが、これはエンティティ自体が永続化するように指示された場合にのみ発生します。Compensatorio のインスタンスを作成するときに、ID を明示的に設定することはなく、そこに引用したその行に到達すると、compensatoriosNewCompensatorioToAttach.getId() は null を返します。
JPAのようなORMには到達可能性による永続性があり、オブジェクトAがオブジェクトBに関連している場合、Aを永続化するとBも永続化されることを理解しています。しかし、この場合、非常に不便な方法で実装されているようです(少なくともコレクションを所有するオブジェクトを永続化し、そのコレクション内のオブジェクトを自動的に永続化する方が便利な場合に、コレクションのすべてのオブジェクトを明示的に永続化する必要があるためです。
私が間違っていることはありますか?、別の角度からこの問題に直面する必要があるかもしれませんが、どのように、またはもしあれば、どの角度から?. netbeans の人々がそのテンプレートをそのように作成するのはなぜですか?そのメソッドを実行して DB 内のオブジェクトを検索し、それを永続化コンテキストに持ち込むと便利なのはなぜですか?すべてのオブジェクトを自分で永続化する必要がありますか? もしそうなら、持続性が一方向にしかできないのに、到達可能性による持続性があると主張するのはなぜですか。
私はこれで明らかに間違っています.私が求めているのは、それらのエンティティ間の関係をどのように明示する必要があるかについての一貫した説明です.それを機能させるために、そのコレクションのすべてのオブジェクトを永続化する必要はありません。または、そのテンプレートをネットビーンズから削除して、すべての CRUD 操作のコードを自分で作成する必要がある場合は、次のようにします。この場合、どのように進めるのが便利かアドバイスを聞いてください。