【问题标题】:JPA & Criteria API - Select only specific columnsJPA & Criteria API - 仅选择特定列
【发布时间】:2012-09-19 01:38:22
【问题描述】:

我只想选择特定的列(例如SELECT a FROM b)。我有一个通用的 DAO,我想出的是:

public List<T> getAll(boolean idAndVersionOnly) {
    CriteriaBuilder builder = manager.getCriteriaBuilder();
    CriteriaQuery<T> criteria = builder.createQuery(entityClazz);
    Root<T> root = criteria.from(entityClazz);
    if (idAndVersionOnly) {
        criteria.select(root.get("ID").get("VERSION")); // HERE IS ERROR
    } else {
        criteria.select(root);
    }
    return manager.createQuery(criteria).getResultList();
}

错误是: The method select(Selection&lt;? extends T&gt;) in the type CriteriaQuery&lt;T&gt; is not applicable for the arguments (Path&lt;Object&gt;)。我应该如何改变它?我想得到一个类型为T 的对象,它只有IDVERSION 字段,而其他所有字段都是null

类型 T 扩展 AbstractEntity 具有这两个字段。

entityClazzT.class

【问题讨论】:

    标签: java hibernate jpa criteria-api


    【解决方案1】:

    仅获取特定列的 JPA 方法之一是请求 Tuple 对象。

    在你的情况下,你需要这样写:

    CriteriaQuery<Tuple> cq = builder.createTupleQuery();
    // write the Root, Path elements as usual
    Root<EntityClazz> root = cq.from(EntityClazz.class);
    cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION));  //using metamodel
    List<Tuple> tupleResult = em.createQuery(cq).getResultList();
    for (Tuple t : tupleResult) {
        Long id = (Long) t.get(0);
        Long version = (Long) t.get(1);
    }
    

    如果您有一个代表结果的类,则可以使用另一种方法,例如 T 在您的情况下。 T 不需要是实体类。如果T 有这样的构造函数:

    public T(Long id, Long version)
    

    那么你可以直接在你的CriteriaQuery构造函数中使用T

    CriteriaQuery<T> cq = builder.createQuery(T.class);
    // write the Root, Path elements as usual
    Root<EntityClazz> root = cq.from(EntityClazz.class);
    cq.multiselect(root.get(EntityClazz_.ID), root.get(EntityClazz_.VERSION));  //using metamodel
    List<T> result = em.createQuery(cq).getResultList();
    

    请参阅此link 以获取更多参考。

    【讨论】:

      【解决方案2】:
      cq.select(cb.construct(entityClazz.class, root.get("ID"), root.get("VERSION")));  // HERE IS NO ERROR
      

      https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Querying/Criteria#Constructors

      【讨论】:

        【解决方案3】:

        首先,我真的不明白为什么你会想要一个只有 ID 和 Version 的对象,而所有其他道具都是空值。但是,这里有一些代码可以为您做到这一点(它不使用 JPA Em,而是使用普通的 Hibernate。我假设您可以在 JPA 中找到等价物,或者简单地从 em 委托获取 Hibernate Session obj Accessing Hibernate Session from EJB using EntityManager ):

        List<T> results = session.createCriteria(entityClazz)
            .setProjection( Projections.projectionList()
                .add( Property.forName("ID") )
                .add( Property.forName("VERSION") )
            )
            .setResultTransformer(Transformers.aliasToBean(entityClazz); 
            .list();
        

        这将返回一个对象列表,其 ID 和版本设置以及所有其他属性为 null,因为 aliasToBean 转换器将无法找到它们。同样,我不确定我是否能想到我想要这样做的情况。

        【讨论】:

        • 谢谢。我想在我的网络服务中使用它。客户端请求仅包含 ID 和版本的“某物”列表。然后他将其与缓存进行比较,并请求更改的完整对象。听起来合理吗?
        • 是为了节省网络带宽吗?我认为它取决于数据,但是如果您希望您的数据经常更改,那么由于创建两个请求的 tcp/ip 开销,您可能会浪费更多的带宽,而不是仅仅发送“空心”副本。也许值得一试?
        • 是的,我知道。我只会将它用于不会经常更改的数据。
        • 好吧,我在 JPA 2 中找不到类似的东西:/
        【解决方案4】:

        你可以这样做

        Session session = app.factory.openSession();
        CriteriaBuilder builder = session.getCriteriaBuilder();
        CriteriaQuery query = builder.createQuery();
        Root<Users> root = query.from(Users.class);
        query.select(root.get("firstname"));
        String name = session.createQuery(query).getSingleResult();
        

        您可以在其中将“名字”更改为所需列的名称。

        【讨论】:

          猜你喜欢
          • 2011-03-29
          • 2014-09-02
          • 1970-01-01
          • 2019-11-10
          • 2015-02-15
          • 2014-03-27
          • 2016-10-31
          • 2014-06-13
          相关资源
          最近更新 更多