I was doing some tutorial (principally for myself) about using the JPA provider in GAE like an advanced API on top of the DataStore API. This is a goal for me to start learning NoSQL and coding well with GAE. After some years using ORMs I think I have a good experience on their use and the way they should behave, but the time to learn something new about things you think you know always shine. One of the tutorial wanted to persist some objects, put the parent key into a request attribute and then redirect to a servlet that shows them. Nothing difficult, but with surprise I was unable to do that in a way I know. Infact at the rendering servlet I always received a null key. Debugging I saw that after the em.persist the key was still not assigned. Really strange I thougth, I used this approach a lot of times in the past and this has nothing to do with Relational or DataStore world, is a matter of specifications. The only way to let it generate the key was a commit the transaction or a flush of the entire session, something that touch the storage in a too aggressive way from my point of view. At first I thought that was a problem regarding the way the GAE DataStore works (I was sure about the fact that I should have the key after persist), so I started developing a test case that uses DataNucleus JPA Engine for a relational DB. A simple test caseFor this test case I used a Maven Project configured with a H2 DataBase instance that run embedded in the application (not for EclipseLink that doesn't support H2, for that I used Oracle 11g) To do that I created a simple Entity with only Id and a persistent field: then I configured the persistence.xml: Running a simple test case showed me that the problem was not in the DataStore but with DataNucleus:
Running the testRunning my test with a simple "mvn clean test" this is what I get: To be sure that everything was correct I did the same test with Hibernate 3.4.0GA, EclipseLink 1.0.1 and OpenJPA 1.0.1 and for all of them:
ConclusionsResuming, I have 4 Persistence Provider and I have 3 of them that work the same way (and this for me is a standard de-facto) but what about JPA1 specs ???From there we can read that (paragraph 3.1.1): "A managed entity instance is an instance with a persistent identity that is currently associated with a persistence context." and because the persist() method of the EntityManager change the state of my Entity from "New" to "Managed" I should have its persistence identity that, paragraph 2.1.4, is in the simpler cases the field/property annotated with @Id. Another test convinced me about a bug in the DataNucleus (and transitively in Google App Engine DataStore). In fact if I change the Id generation type from IDENTITY to AUTO it works like all the others JPA Engine !!!! But wait, from DataNucleus documentation (http://www.datanucleus.org/products/accessplatform_1_1/jpa/value_generation.html) a value of AUTO for H2 DataBase means IDENTITY generation !!!! This is a really annoining bug, because force me to use the JPA API in a really strange way, so I asked on Google App Engine group: AppendixI attached the test project for convenience and in case you want to help me understanding this problem. |