Ошибка обновления каскада JPA. Я делаю это неправильно? - PullRequest
0 голосов
/ 13 января 2010

Я использую JPA в приложении SWING в JAVA, которое подключается к встроенной базе данных Apache DERBY.Я использую 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 в одной части программы и сохраняю их в порядке.Затем в другой части я должен создать и добавить экземпляры Compensatorio в список Compensatorio в экземпляре AnioLectivo.Теперь я хочу сохранить эту модификацию, которая, как я предполагаю, сделана с использованием метода edit в классе 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());

Почему?Хорошо, если вы видите сущности, я определил, что идентификатор всех сущностей должен быть сгенерирован единицей персистентности, но это происходит только тогда, когда самой сущности говорят о сохранении.Когда я создаю экземпляры Compensatorio, я никогда не устанавливаю идентификатор в явном виде, и когда он достигает той строки, которую я там указал, компенсаторiosNewCompensatorioToAttach.getId () возвращает ноль.

Насколько я понимаю, ORM, как и JPA, имеют постоянство по достижимости,это позволяет, что если объект A связан с объектом B, постоянный A также сохраняется B. Но в этом случае кажется, что он реализован очень неудобным способом (по крайней мере для меня), потому что это заставляет меня сохранять каждый объектмоя коллекция в явном виде, когда было бы более полезно сохранить объект, который владеет этой коллекцией, и затем объекты в этой коллекции будут сохранены автоматически

Есть ли что-то, что я делаю не так?другой угол, но я не знаю, как, или если вообще, какой угол ?.Почему люди из NetBeans делают этот шаблон таким образом, почему полезно выполнить этот метод, чтобы попытаться найти объекты в БД и перенести его в контекст постоянства, нужно ли мне сохранять каждый объект самостоятельно?если это так, то почему они утверждают, что обладают настойчивостью по достижимости, если настойчивость может быть достигнута только в одном направлении.

Я совершенно не прав в этом, то, что я ищу, это последовательное объяснение того, как быдолжны быть объяснены отношения между этими объектами (если я действительно допустил ошибку в способе, которым я их создал, потому что в каждой книге и учебнике, который я прочитал, это делается так), чтобы заставить его работать, поэтому мне не нужно сохранять каждый объектэтой коллекции или, если мне нужно удалить этот шаблон из netbeans и самостоятельно создать код для всех операций CRUD, я хотел бы услышать совет о том, как удобно действовать в этом случае.

1 Ответ

0 голосов
/ 13 января 2010

Похоже, что вы можете позвонить em.merge(anioLectivo) вместо всего этого кода.

...