我在JAVA中的SWING应用程序上使用JPA,它连接到Apache DERBY嵌入式数据库。我使用Netbeans作为我的IDE并使用许多“可能”有用的模板。我的问题很简单,但我很难解释,所以我会在这里粘贴相关的代码并尝试在底部解释。JPA级联更新错误。我这样做是错误的吗?
@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;
...
}
这两个是我想要坚持的实体。
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);
...
}
这是一个netbeans使用我之前粘贴的实体AnioLectivo的注释生成的类。正如你所看到的,我只粘贴了与问题相关的代码以保持简单,因为我知道感谢netbeans的调试工具,问题出在这里。 现在我将尝试解释到底发生了什么。
我在程序的一部分中创建AnioLectivo的实例并坚持它们。然后在另一部分中,我必须在AnioLectivo的实例中创建Compensatorio的实例并将其添加到Compensatorio的列表中。现在,我要保存这个修改,我认为使用类AnioLectivoJpaController编辑方法制成,我发现这个错误:
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的编辑方法:
em.getReference(compensatoriosNewCompensatorioToAttach.getClass(),
compensatoriosNewCompensatorioToAttach.getId());
为什么?那么如果你看到这些实体,我已经定义了所有实体的id都是由持久化单元生成的,但是这只有当实体本身被告知要坚持时才会发生。当我创建Compensatorio的实例时,我从来没有明确设置id,并且当它到达我在那里引用的那一行时,compensatoriosNewCompensatorioToAttach.getId()返回null。
我的理解是,ORM像JPA具有可达性持久性,它允许如果对象A与对象B相关,持久A也会持续B.但是在这种情况下,它看起来像是以非常不方便的方式实现的(至少对我而言),因为它会强制我明确地持久存储集合中的每个对象,如果持久化拥有该集合的对象并且然后该集合中的对象会自动保留,那么它会自动保留
是否有某种东西我做错了?也许我应该从另一个角度面对这个问题,但我不知道如何,或者如果有的话,是什么角度?为什么netbeans的人以这种方式制作该模板,为什么执行该方法试图搜索数据库中的对象并将其带入持久化上下文是有用的,我是否需要自己坚持每个对象?如果这就是为什么他们声称拥有可持续持久性(Persistence by Reachability),那么如果持久性只能在一个方向上进行。
我明显在这个错误,我正在寻求它是一个连贯的解释,将如何阐明这些实体之间的关系(如果我实际上在我创造他们的方式犯了一个错误,因为在每一个书和教程,我读它是这样做的),使其工作,所以我不需要坚持该集合的每一个对象,或者,如果我需要从netbeans中删除该模板,并使自己的所有CRUD操作的代码,我希望听到关于在这种情况下如何方便进行的建议。