我目前正在将基于 JPA-2.0 的应用程序从 Hibernate 迁移到 Google App Engine,因为我只想在那里运行它。
我被困住了,因为我无法从 SELECT 查询中获得任何结果。我可以持久化实体并通过 id 找到它们,但是如果我想使用 SELECT 查询检索所有现有实体,则结果为空。
我在一个简单的测试用例中隔离了这个问题:
持久性.xml
<?xml version="1.0" encoding="UTF-8" ?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0">
<persistence-unit name="google.transactions-optional">
<provider>org.datanucleus.api.jpa.PersistenceProviderImpl</provider>
<properties>
<property name="datanucleus.NontransactionalRead" value="true"/>
<property name="datanucleus.NontransactionalWrite" value="true"/>
<property name="datanucleus.ConnectionURL" value="appengine"/>
<property name="datanucleus.singletonEMFForName" value="true"/>^
</properties>
</persistence-unit>
</persistence>
JPA 实体类
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
class TestEntity
{
@Id
String id;
String name;
TestEntity(String id, String name)
{
this.id = id;
this.name = name;
}
// For deseralization
@SuppressWarnings("unused")
private TestEntity()
{
}
}
失败的 JUnit 测试
import org.junit.*;
import static org.junit.Assert.*;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.TypedQuery;
import com.google.appengine.tools.development.testing.LocalDatastoreServiceTestConfig;
import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
public class SimpleJpaTest
{
private static final String PERSISTENCE_UNIT = "google.transactions-optional";
private static final EntityManagerFactory EMF = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT);
private final LocalServiceTestHelper _helper;
public SimpleJpaTest()
{
_helper = new LocalServiceTestHelper(new LocalDatastoreServiceTestConfig().setDefaultHighRepJobPolicyUnappliedJobPercentage(100));
}
@Before
public void setUp()
{
_helper.setUp();
}
@After
public void tearDown()
{
_helper.tearDown();
}
@Test
public void testPersistAndGet()
{
String id = "test";
String name = "Test";
// Persist entity
EntityManager entityManager1 = EMF.createEntityManager();
entityManager1.getTransaction().begin();
TestEntity entity1 = new TestEntity(id, name);
entityManager1.persist(entity1);
entityManager1.getTransaction().commit();
entityManager1.close();
// Find specific entity
EntityManager entityManager2 = EMF.createEntityManager();
entityManager2.getTransaction().begin();
TestEntity result2 = entityManager2.find(TestEntity.class, id);
entityManager2.getTransaction().commit();
entityManager2.close();
assertNotNull(result2); // succeeds
assertEquals(id, result2.id); // succeeds
assertEquals(name, result2.name); // succeeds
// Get all entities
EntityManager entityManager3 = EMF.createEntityManager();
entityManager3.getTransaction().begin();
String queryString3 = "SELECT e from TestEntity e";
TypedQuery<TestEntity> query3 = entityManager3.createQuery(queryString3, TestEntity.class);
List<TestEntity> result3 = query3.getResultList();
entityManager3.getTransaction().commit();
entityManager3.close();
assertNotNull(result3); // succeeds
assertFalse(result3.isEmpty()); // fails
assertEquals(1, result3.size());
assertNotNull(result3.get(0));
assertEquals(id, result3.get(0).id);
assertEquals(name, result3.get(0).name);
}
}
如您所见,通过 find() 检索单个实体效果很好,但 SELECT 查询却不行。相同的代码适用于 Hibernate。
根据 DataNucleus 的评论进行编辑:
控制台输出
Jan 30, 2013 2:41:10 PM org.datanucleus.metadata.MetaDataManager loadPersistenceUnit
WARNING: Class SimpleJpaTest was specified in persistence-unit google.transactions-optional but not annotated, so ignoring
Jan 30, 2013 1:41:11 PM com.google.appengine.api.datastore.dev.LocalDatastoreService init
INFO: Local Datastore initialized:
Type: High Replication
Storage: In-memory
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl internalPreCommit
INFO: >> calling preCommit on org.datanucleus.store.connection.ConnectionManagerImpl$2@15b573da
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl internalPreCommit
INFO: >> calling preCommit on org.datanucleus.ObjectManagerImpl@5ede1ffa
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl preFlush
INFO: >> calling preFlush on org.datanucleus.store.connection.ConnectionManagerImpl$2@15b573da
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl preFlush
INFO: >> calling preFlush on org.datanucleus.ObjectManagerImpl@5ede1ffa
Jan 30, 2013 1:41:11 PM com.google.appengine.datanucleus.MetaDataValidator validate
INFO: Performing appengine-specific metadata validation for TestEntity
Jan 30, 2013 1:41:11 PM com.google.appengine.datanucleus.MetaDataValidator validate
INFO: Finished performing appengine-specific metadata validation for TestEntity
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl internalPreCommit
INFO: >> calling preCommit on org.datanucleus.store.connection.ConnectionManagerImpl$2@49c54f01
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl internalPreCommit
INFO: >> calling preCommit on org.datanucleus.ObjectManagerImpl@69eeff74
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl preFlush
INFO: >> calling preFlush on org.datanucleus.store.connection.ConnectionManagerImpl$2@49c54f01
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl preFlush
INFO: >> calling preFlush on org.datanucleus.ObjectManagerImpl@69eeff74
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl preFlush
INFO: >> calling preFlush on org.datanucleus.store.connection.ConnectionManagerImpl$2@16f650e5
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl preFlush
INFO: >> calling preFlush on org.datanucleus.ObjectManagerImpl@71fcf7e2
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl internalPreCommit
INFO: >> calling preCommit on org.datanucleus.store.connection.ConnectionManagerImpl$2@16f650e5
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl internalPreCommit
INFO: >> calling preCommit on org.datanucleus.ObjectManagerImpl@71fcf7e2
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl preFlush
INFO: >> calling preFlush on org.datanucleus.store.connection.ConnectionManagerImpl$2@16f650e5
Jan 30, 2013 1:41:11 PM org.datanucleus.TransactionImpl preFlush
INFO: >> calling preFlush on org.datanucleus.ObjectManagerImpl@71fcf7e2
顺便说一句:这个问题似乎类似于Google App Engine + google cloud sql jpa query does not retrieve data from database,但还没有答案。