Unable to read after commit () with JPA

C

carmelo

Hello everybody,
I developed a CRUD application using TopLink Essentials as persistence
provider. I've got the following problem:

I have to save data according to the master-details scheme, but I can
not read that unless restarting the application, even if they are
already physically on the database before restarting.

In practice, I read master/details of an offer and transform them into
master/details of an order, storing them on db.

Since these data are generated within another transaction, I created
another EntityManager called entityManager2.

This is the code I'm using:

org.jdesktop.application.ResourceMap resourceMap =
org.jdesktop.application.Application.getInstance(desktopapplication_db_advanced.DesktopApplication_db_advanced.class).getContext().getResourceMap(OffertaEditor.class);
EntityManager entityManager2 =
javax.persistence.Persistence.createEntityManagerFactory(resourceMap.getString("entityManager.persistenceUnit")).createEntityManager();
try {
entityManager2.getTransaction().begin();
int numOrdine = 0;
Object res = entityManager2.createQuery("SELECT
MAX(o.numOrdine) FROM Ordini o WHERE o.anno
= :anno").setParameter("anno", anno).getSingleResult();
entityManager2.getTransaction().commit();
if (res != null) {
numOrdine = (Integer) res;
}
numOrdine++;
numOrdineField.setText(String.valueOf(numOrdine));

//create order from offer

entityManager2.getTransaction().begin();

//master order
int index = masterTable.getSelectedRow();
offerta.Offerte of =
list.get(masterTable.convertRowIndexToModel(index));
ordine.Ordini ord = new ordine.Ordini();

ord.setCodiceCliente(Integer.parseInt(clienteField.getText()));
ord.setNumOfferta(of.getNumOfferta());
ord.setNumOrdine(numOrdine);
entityManager2.persist(ord);
//details order
Collection<offerta.Dettofferte> ds = of.getDettofferteList();
Iterator<offerta.Dettofferte> iter = ds.iterator();
int rows = detailTable.getRowCount();
for (int idx = 0; idx < rows; idx++) {
offerta.Dettofferte dettoff = iter.next();
ordine.Dettordini dettord = new Dettordini();
dettord.setCodiceArticolo(dettoff.getCodiceArticolo());
dettord.setDescrizione(dettoff.getDescrizione());
dettord.setNumOrdine(numOrdine);
dettord.setPrezzo(dettoff.getPrezzo());
dettord.setQuantita(dettoff.getQuantita());
dettord.setTotale(dettoff.getTotale());

entityManager2.persist(dettord);
dettord.setCodiceOrdine(ord);
}

entityManager2.getTransaction().commit();
entityManager2.close();

} catch (RollbackException rex) {
rex.printStackTrace();
entityManager2.getTransaction().rollback();
entityManager2.close();
}


Would you have any advice?

I hope you can help me. Thank you very much in advance!
 
R

Robert Klemme

Hello everybody,
I developed a CRUD application using TopLink Essentials as persistence
provider. I've got the following problem:

I have to save data according to the master-details scheme, but I can
not read that unless restarting the application, even if they are
already physically on the database before restarting.

In practice, I read master/details of an offer and transform them into
master/details of an order, storing them on db.

Since these data are generated within another transaction, I created
another EntityManager called entityManager2.

Without knowing Toplink myself I believe having a second EM for the
*same* schema is a bad idea. Typically an EM assumes that you access a
particular set of data only through it - so consequently (because of its
caching and remembering of persistent state) it won't see changes made
through another EM. The fact that two TX are involved does not create
necessity to have two EM. Only if you need to access different data
sources you would need more than one EM.
This is the code I'm using:

I see only one EM in that code. It seems this does not give the whole
picture.

Kind regards

robert
 
C

carmelo

Thank you for your reply Robert.

I try to describe the whole picture:

I have 2 JFrame
- one is for CRUD operations on Offer (and for transforming master/
details offer into master/details order), lets call it frmOfferEditor
- one is for searching Order created by frmOfferEditor, lets call it
frmOrderSearch

/* frmOfferEditor */

//transform
The code I posted before it's the code I'm using on frmEditor when I
need transforming master/details offer into master/details order.

//CRUD
The code I use for CRUD operations uses an EM called entityManager.
Here is the code:

//CRUD - Create
try {
entityManager.getTransaction().rollback();
entityManager.getTransaction().begin();
offerta = new offerta.Offerte();
numOfferta = 0;
Object res = entityManager.createQuery("SELECT MAX(o.numOfferta) FROM
Offerte o WHERE o.anno = :anno").setParameter("anno",
anno).getSingleResult();
if (res != null) {
numOfferta = (Integer) res;
}
numOfferta++;
offerta.setNumOfferta(numOfferta);
entityManager.persist(offerta);
} catch (Exception ex) {
ex.printStackTrace();
}

// CRUD - Save
try {
entityManager.getTransaction().commit();
entityManager.getTransaction().begin();
} catch (RollbackException rex) {
rex.printStackTrace();
entityManager.getTransaction().begin();
List<offerta.Offerte> merged = new
ArrayList<offerta.Offerte>(list.size());
for (offerta.Offerte o : list) {
merged.add(entityManager.merge(o));
}
list.clear();
list.addAll(merged);
}


/* frmOrderSearch */
try {
entityManager.getTransaction().rollback();
entityManager.getTransaction().begin();
String query = ....
Query q = entityManager.createQuery(query).setParameter(.....)
java.util.Collection data = q.getResultList();
list.clear();
list.addAll(data);
} catch (Exception ex) {
ex.printStackTrace();
}


I hope that now it's clear
 
R

Robert Klemme

Thank you for your reply Robert.

I try to describe the whole picture:

I have 2 JFrame
- one is for CRUD operations on Offer (and for transforming master/
details offer into master/details order), lets call it frmOfferEditor
- one is for searching Order created by frmOfferEditor, lets call it
frmOrderSearch
I hope that now it's clear

I still fail to see why you think you need two EM. If the data is
sitting in the same location (same schema in the same DB server accessed
through the same user), then you only need one. Also, with a clean MVP
separation you would not bother how many UI elements access the data.
To me it seems you have an application design issue.

Kind regards

robert
 
L

Lew

carmelo said:
I developed a CRUD application using TopLink Essentials as persistence
provider. I've got the following problem:

These days "[a]s of Oracle TopLink 11g, TopLink Essentials has been replaced
with EclipseLink JPA. EclipseLink JPA implements JPA 1.0 and is responsible
for delivering the persistence framework."
I have to save data according to the master-details scheme, but I can
not read that unless restarting the application, even if they are
already physically on the database before restarting.

In practice, I read master/details of an offer and transform them into
master/details of an order, storing them on db.

Since these data are generated within another transaction, I created
another EntityManager called entityManager2.

Robert addressed this point.
This is the code I'm using:

org.jdesktop.application.ResourceMap resourceMap =
org.jdesktop.application.Application.getInstance(desktopapplication_db_advanced.DesktopApplication_db_advanced.class).getContext().getResourceMap(OffertaEditor.class);
EntityManager entityManager2 =

That package name does not conform to the naming conventions.

You're not providing an SSCCE, and you should.

Use imports to make your code more readable.
javax.persistence.Persistence.createEntityManagerFactory(resourceMap.getString("entityManager.persistenceUnit")).createEntityManager();
try {
entityManager2.getTransaction().begin();
int numOrdine = 0;
Object res = entityManager2.createQuery("SELECT
MAX(o.numOrdine) FROM Ordini o WHERE o.anno
= :anno").setParameter("anno", anno).getSingleResult();
entityManager2.getTransaction().commit();

A transaction for a SELECT??

And you declared the variable 'Object'. Tsk, tsk.
if (res != null) {
numOrdine = (Integer) res;
}
numOrdine++;
numOrdineField.setText(String.valueOf(numOrdine));

As Robert said, lack of MVC separation here shows that you have a messed-up
design.
//create order from offer

entityManager2.getTransaction().begin();

//master order
int index = masterTable.getSelectedRow();

Huh? 'masterTable'? What's that?
offerta.Offerte of =
list.get(masterTable.convertRowIndexToModel(index));

Huh? 'list'? What's that?
ordine.Ordini ord = new ordine.Ordini();

ord.setCodiceCliente(Integer.parseInt(clienteField.getText()));
ord.setNumOfferta(of.getNumOfferta());
ord.setNumOrdine(numOrdine);
entityManager2.persist(ord);
//details order
Collection<offerta.Dettofferte> ds = of.getDettofferteList();
Iterator<offerta.Dettofferte> iter = ds.iterator();
int rows = detailTable.getRowCount();

Huh? 'detailTable'? What's that?
for (int idx = 0; idx< rows; idx++) {
offerta.Dettofferte dettoff = iter.next();
ordine.Dettordini dettord = new Dettordini();
dettord.setCodiceArticolo(dettoff.getCodiceArticolo());
dettord.setDescrizione(dettoff.getDescrizione());
dettord.setNumOrdine(numOrdine);
dettord.setPrezzo(dettoff.getPrezzo());
dettord.setQuantita(dettoff.getQuantita());
dettord.setTotale(dettoff.getTotale());

entityManager2.persist(dettord);
dettord.setCodiceOrdine(ord);
}

entityManager2.getTransaction().commit();
entityManager2.close();

'close()' should be in a 'finally' block.
} catch (RollbackException rex) {
rex.printStackTrace();
entityManager2.getTransaction().rollback();
entityManager2.close();
}


Would you have any advice?

I hope you can help me. Thank you very much in advance!

The point of JPA is to give the application an object model of data. I don't
see that here.
 
R

Robert Klemme

Solved!
The problem was on reading... it was necessary to synchronize entities
with a loop of entityManager.refresh(entity);

So you sticked with your two EntityManagers? In that case you have at
best a workaround - but not a proper solution.

Good luck!

robert
 
A

Arved Sandstrom

Robert said:
So you sticked with your two EntityManagers? In that case you have at
best a workaround - but not a proper solution.

Good luck!

robert
And in my experience - admittedly anecdotal - refresh() doesn't figure
all that much. It's usually not the proper choice if your understanding
of JPA isn't solid.

In a couple of largish J2EE applications that I have worked with
extensively over the past while, the *only* use of refresh is for
operations support people who have to do manual database work to
fix/reverse certain actions in the field; refresh() is used on the
entities that have just been modified directly, because we can't restart
the application. That is, there is "backout" functionality in the app
for refreshing entities that are known to have been changed.

I have to agree with Robert, this doesn't feel like a solution.

AHS
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,190
Members
46,736
Latest member
zacharyharris

Latest Threads

Top