Hi Tim,
We've been working on our SWT/RCP CRUD application and are running
into a strange anomaly. Example:
*Open Editor (this creates a new model & hence a new EntityManager)
*Change Field Value: this calls, merge on our EntityManager
*Editor is marked dirty, since em.getUnitOfWork().hasChanges() returns true.
*Close editor, do not save changes.
*Open up same record again in a new editor, my changes are still there
and em.getUnitOfWork().hasChanges() returns false.
When you rollback a transaction the state of the entities you read is
not changed. You should discard them and reread new managed instances
that will reflect the correct state.
Some other things to watch out for include use of
properties.put(PersistenceUnitProperties.CACHE_SHARED_DEFAULT, "false");
You want to use the shared cache by default. I mistakenly included
this in the examples I checked into SVN.
Another is that entityManager.merge(..) returns the object that the
changes were merged into. Keeping straight what is the managed vs.
unmanaged instances can be tough. Since you have a transaction open
anyway why are you calling merge? And how do you obtain references to
the entities you're editing?
On reflection, I realize that UnitOfWork.hasChanges() can be expensive
because it has to calculate changes--just like it has to do at commit
time. Byte code weaving (and change tracking) would make this cheaper
but it isn't working at this point in OSGi. Can you determine whether
you need to commit some other way like editor field value changes?
Also, you need to be careful with threads. EntityManagers are not
guaranteed thread safe. In my RCP example I never got around to
ensuring that concurrent threads spawned by the UI were not all
executing queries in parallel--it was on
my To Do list but the example did enough to make me happy so I've left
it where it is. ;-)
Shaun
Obviously there is some sort of caching going on, so what is the
correct way to discard changes to my transaction?
Backup Code:
Creating my EntityManagerFactory:
properties.put(PersistenceUnitProperties.TARGET_DATABASE, "Derby");
properties.put(PersistenceUnitProperties.JDBC_DRIVER,
"org.apache.derby.jdbc.ClientDriver");
properties.put(PersistenceUnitProperties.JDBC_URL,
"jdbc:derby://localhost:1527/sample;create=true");
properties.put(PersistenceUnitProperties.JDBC_USER, "app");
properties.put(PersistenceUnitProperties.JDBC_PASSWORD, "app");
properties.put(PersistenceUnitProperties.JDBC_READ_CONNECTIONS_MIN, "1");
properties.put(PersistenceUnitProperties.JDBC_WRITE_CONNECTIONS_MIN, "1");
properties.put(PersistenceUnitProperties.CACHE_SHARED_DEFAULT, "false");
properties.put(PersistenceUnitProperties.BATCH_WRITING, "JDBC");
properties.put("eclipselink.logging.level", "FINE");
properties.put("eclipselink.logging.timestamp", "false");
properties.put("eclipselink.logging.session", "false");
properties.put("eclipselink.logging.thread", "false");
emf = new PersistenceProvider().createEntityManagerFactory("comics",
properties, ComicsEntityManagerFactory.class.getClassLoader());
}
The "Model" that is created when an editor is opened:
public class PublisherEditorModel {
private EntityManager em;
private EntityTransaction transaction;
public PublisherEditorModel() {
em = ComicsEntityManagerFactory.createEntityManager();
transaction = em.getTransaction();
transaction.begin();
}
public void close() {
transaction.rollback();
em.close();
}
public void updatePublisher(Publisher publisher) {
em.merge(publisher);
}
public void updateTitle(Title title) {
em.merge(title);
}
public void save() {
transaction.commit();
}
public boolean isDirty() {
UnitOfWork uow = ((EntityManagerImpl)em).getUnitOfWork();
return uow.hasChanges();
}
}
--
Shaun Smith | Principal Product Manager, TopLink |
+1.905.502.3094
Oracle Fusion Middleware
110 Matheson Boulevard West, Suite 100
Mississauga, Ontario, Canada L5R 3P4
|