JPA级联更新错误。我这样做是错误的吗?

时间:2010-01-13 19:51:25

标签: java swing jpa persistence derby

我在JAVA中连接到Apache DERBY嵌入式数据库的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;  
...  
}  

这两个是我想要坚持的实体。

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的List。现在我想保存这个修改,我假设是使用类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的编辑方法中的这行代码中:

em.getReference(compensatoriosNewCompensatorioToAttach.getClass(),
                compensatoriosNewCompensatorioToAttach.getId());

为什么呢?好吧,如果你看到实体,我已经定义了所有实体的id将由持久性单元生成,但这仅在实体本身被告知持久时才会发生。当我创建Compensatorio的实例时,我从未明确地设置id,当它到达那条线时我引用了那里,compensatoriosNewCompensatorioToAttach.getId()返回null。

我的理解是,像JPA这样的ORM具有可持续性的持久性,允许如果对象A与对象B相关,则持久性A也持续存在B.但在这种情况下,它似乎以非常不方便的方式实现(至少对我而言),因为它强制我明确地持久保存我的集合中的每个对象,因为持久化拥有该集合的对象然后自动持久保存该集合中的对象

有什么我做错了吗?也许我应该从另一个角度面对这个问题,但我不知道怎么样,或者是否有什么角度?为什么netbeans的人以这种方式创建该模板,为什么执行该方法尝试搜索数据库中的对象并将其带到持久化上下文时,为什么我需要自己保留每个对象?如果是这样的话,为什么如果持久性只能在一个方向上进行,他们会声称具有可达性持久性。

我在这方面显然是错的,我正在寻求它是如何必须解释这些实体之间的关系的连贯解释(如果我实际上在我创建它们的方式上犯了错误,因为在每本书中和教程我读它像这样做)使其工作,所以我不需要坚持该集合的每个对象,或者,如果我需要从netbeans删除该模板,并自己制作所有CRUD操作的代码,我我想听听有关在这种情况下如何方便的建议。

1 个答案:

答案 0 :(得分:0)

似乎您可以拨打em.merge(anioLectivo)而不是所有这些代码。