views:

350

answers:

2

Hi everyone, i'm using JPA on a SWING application in JAVA that connects to an Apache DERBY embedded database. I use Netbeans as my IDE and use many of the "suposedly" helpfull templates. My problem it's simple, but it's dificult for me to explain so i will paste the relevant code here and try to explain at the bottom.

@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;  
...  
}  

These two are the entities that i want to persist.

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);
        ...
}

This is a class that netbeans generates using the anotations of the entity AnioLectivo that i pasted before. As you can see, i only pasted the code relevant to the problem to keep it simple because i know thanks to the debug tool of netbeans that the problem is here. Now i'll try to explain exactly what happens.

I create instances of AnioLectivo in one part of the program and persist them ok. Then in another part i must create and add instances of Compensatorio to the Compensatorio's List in an instance of AnioLectivo. Now i want to save this modification, wich i assume it's made using the edit method in the class AnioLectivoJpaController and i found this error:

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) ...

the problem, as i see it, ocurrs in this line of code in the edit method of AnioLectivoJpaController: em.getReference(compensatoriosNewCompensatorioToAttach.getClass(), compensatoriosNewCompensatorioToAttach.getId());

Why?, well if you see the entities, i have defined that the id of all entities it's to be generated by the persistence unit, but this only happens when the entity itself is told to persist. As i create the Compensatorio's instances i never set the id explicitly and when it arrives to that line i quoted up there, compensatoriosNewCompensatorioToAttach.getId() returns null.

It's my understanding that ORM's like JPA have Persistence by Reachability, that allows that if an object A is related to an object B, persisting A also persists B. But in this case it seems like it's implemented in a very inconvenient way(at least for me), because it forces me to persist every object of my collection explicitly when it would be more usefull to persist the object that owns that collection and then the objects in that collection be persisted automatically

Is there something i'm doing wrong?, maybe i should face this problem from another angle, but i don't know how, or if any, what angle?. Why does the people of netbeans make that template that way, why is it usefull to execute that method to try to search the objects in the DB and bring it to the persistence context, do i need to persist every object myself? if that's so why do they claim to have Persistence by Reachability if the persistence can only be made in one direction only.

I'm clearly wrong in this, what i'm seeking it's a coherent explanation of how would have to be explicited the relationship between those entities(if i actually did a mistake in the way i created them, because in every book and tutorial i read it's done like that) to make it work so i don't need to persist every object of that collection, or, if i need to drop that template from netbeans and make the code for all the CRUD operations myself, i will like to hear advice on how is convenient to proceed in this case.

Thanks in advance, and please forgive the long of this post and my poor english.

A: 

It seems to be you can call em.merge(anioLectivo) insted of all this code.

axtavt
A: 

Hi, thanks for your answer, i think it might be the simplest way, to write the CRUD operations for the ORM myself, but besides that i was looking to learn, if anyone can tell me, why is that chunk of code (generated by netbeans) necesary, i mean is it done that way to save me from other problem i don't know right now or i'm not foreseeing?, because if not, what you say would be the way to go. But they must have make that code for one reason.

thanks again

Julian