投影查询:如何使用 JPA 为 AppEngine 中的新实体加载原始字符串?

Posted

技术标签:

【中文标题】投影查询:如何使用 JPA 为 AppEngine 中的新实体加载原始字符串?【英文标题】:Projection Queries: How to load raw String using JPA for new Entity in AppEngine? 【发布时间】:2013-10-18 14:23:55 【问题描述】:

如何在 AppEngine 中为一个全新的、空的、不存在的表加载字符串列表?我试着按照这个例子:

http://www.objectdb.com/java/jpa/query/jpql/select#Projection_of_Path_Expressions_

但它给了我一个错误:

原因:javax.persistence.PersistenceException:用于查询的类 AdminUser 尚未解决。检查查询和任何导入/别名规范

原因:org.datanucleus.exceptions.ClassNotResolvedException:用于查询的类 AdminUser 尚未解决。检查查询和任何导入/别名规范

代码如下:

public java.util.List<String> getAdmin() 
    EntityManager em = EMF.get().createEntityManager();
    try 
        TypedQuery<String> tq = em.createQuery("select au.email from AdminUser as au", String.class);
        return tq.getResultList();  ///// <=== EXCEPTION

我实际上并不想使用 AdminUser 类。我只想要一列字符串。如何在 AppEngine 上创建一个新的空表并不明显。

【问题讨论】:

如果您不想创建 AdminUser 类,请不要引用。首先阅读 JPA 规范和关于 JPQL 的部分,然后参考您实际拥有的类。为什么不提你有什么课?以及您要选择该课程的哪个领域? @DataNucleus 这非常无用。你看过示例链接吗? 读者的角色是制作 cmets,以便提问的人实际上提出了一个可以理解的问题;这目前不是。如果你使用 JPA,你有一些类、一些元数据、一些持久性代码、一些查询。你想“加载字符串列表”......它在哪里?您不说,而是继续创建“空表”。澄清你的问题是第一步 @DataNucleus 抱歉,我无法帮助您进行阅读理解。我的问题就足够了。您提出的所有问题都存在。 【参考方案1】:

GAE Datastore 是一个无模式 NoSQL 数据库。没有桌子。只有实体必须具有种类、ID 并且可以具有任意一组属性。

您可以使用Datastore via JPA API,而不是low-level untyped entities,为您提供漂亮的类型化Java 类。

【讨论】:

是的,我已经读过,但它没有说明如何创建一个空表/实体。在创建要插入的行之前,我需要先从表中读取。通常对于Web应用程序,您可以直接进入数据库并创建一个表。您是说 Google AppEngine 不支持创建表/实体来引导 Web 应用程序吗? 没错,没有架构,所以没有要定义的表。 GAE 上有超过 10 万个应用程序,所以他们一定做对了,对吧? 另外,您的 JPA 异常似乎是由于您没有定义 AdminUser 类。这与 AppEngine 或其数据存储无关。 JPA 是一个帮助库,将数据从数据库映射到 Java 类。 我会说,这个大洞应该是你的礼仪,而不是谷歌的 appengine 设计。【参考方案2】:

AppEngine 不支持示例链接中的 JPA 原始原始查询。我必须直接使用 DatastoreService API。这是我尝试过的。需要进行一些清洁,因为很多东西都不起作用,但确实如此。

    public java.util.List<String> getAdmin() 
        log.info("getAdmin()");

        // AppEngine does not support strong consistency... will frequently return stale results. Setting read policy won't work.
        // Construct a read policy for strong consistency
        ReadPolicy policy = new ReadPolicy(ReadPolicy.Consistency.STRONG);
        // Set the read policy
        DatastoreServiceConfig consistentConfig = DatastoreServiceConfig.Builder.withReadPolicy(policy);
        // Get Datastore service with the given configuration
        DatastoreService datastoreService =  DatastoreServiceFactory.getDatastoreService(consistentConfig);

        com.google.appengine.api.datastore.Query query  = new com.google.appengine.api.datastore.Query("AdminUser");
//      DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
        java.util.List<Entity> events = datastoreService.prepare(query).asList(FetchOptions.Builder.withDefaults());
        ArrayList<String> al = new ArrayList<String>();
        for(Entity entity: events) 
            String s = entity.getProperty("email").toString();
            al.add(s);
        
        if(true) return al; 


        @SuppressWarnings("unused")
        EntityManager em = EMF.get().createEntityManager();
        try 
            TypedQuery<String> tq = em.createQuery("select au.email from AdminUser as au", String.class);
            return tq.getResultList();
         catch (ClassNotResolvedException | javax.persistence.PersistenceException cnre) 
            // catch the exception because AppEngine DataStore has no way to create a new empty Entity table.
            log.warning("AdminUser entity does not exist or is empty.");
            return new java.util.ArrayList<String>();
         finally 
            em.close(); 
        

//      log.info("getAdmin(): al.size(): " + al.size());
    


    public void setAdmin(java.util.List<String> admin) 
        log.info("setAdmin(), admin.size():"+admin.size());

        // delete all AdminUsers
        com.google.appengine.api.datastore.Query query  = new com.google.appengine.api.datastore.Query("AdminUser");
        DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
        java.util.List<Entity> events = datastoreService.prepare(query).asList(FetchOptions.Builder.withDefaults());
        for(Entity entity: events) 
            datastoreService.delete(entity.getKey());
        


//      EntityManager em = EMF.get().createEntityManager();
//      Query q = em.createQuery("delete from AdminUser");
//      q.executeUpdate();


//      DatastoreService datastoreService = DatastoreServiceFactory.getDatastoreService();
        for (String s: admin) 
            log.info("creating AdminUser Entity...");
            Entity e = new Entity("AdminUser");
            e.setProperty("email", s);
            datastoreService.put(e);    
        
        // Must wait for Datastore to actually write records. Ignores consistency even with strong consistency set.
        // this doesn't even work sometimes...
        //try  Thread.sleep(5000);  catch (InterruptedException e) 

//      EntityManager em = EMF.get().createEntityManager();
//      for (String s: admin) 
//          Entity e = new Entity("AdminUser");
//          e.setProperty("email", s);
//          em.persist(e);
//      
//      em.close();

     // setAdmin()

【讨论】:

以上是关于投影查询:如何使用 JPA 为 AppEngine 中的新实体加载原始字符串?的主要内容,如果未能解决你的问题,请参考以下文章

Spring-data-jpa 投影生成查询不正确

Spring JPA - “java.lang.IllegalArgumentException:投影类型必须是接口!” (使用本机查询)

Java AppEngine:JDO还是JPA,如何选择? [关闭]

Spring Data JPA 通过查询从实体获取投影

带有列表的 JPA CriteriaQuery 投影

如何在 Spring Data JPA 中使用带有分页的投影接口?