JPA @ Google App Engine:JPQL SELECT查询始终返回空结果

时间:2013-01-30 13:16:21

标签: google-app-engine jpa jpa-2.0 datanucleus

我目前正在将基于JPA-2.0的应用程序从Hibernate迁移到Google App Engine,因为我只想在那里运行它。

我被困了,因为我无法从SELECT查询中获得任何结果。我可以持久化实体并通过id找到它们,但是如果我想用SELECT查询检索所有现有实体,则结果为空。

我在一个简单的测试用例中分离了这个问题:

的persistence.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-Test失败

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

btw:这个问题似乎与Google App Engine + google cloud sql jpa query does not retrieve data from database类似,但目前还没有答案。

1 个答案:

答案 0 :(得分:0)

我想我继续使用Hibernate并使用Google Cloud SQL比迁移到App Engine Datastore更容易...