JPA & Criteria API - 仅选择特定列
Posted
技术标签:
【中文标题】JPA & Criteria API - 仅选择特定列【英文标题】:JPA & Criteria API - Select only specific columns 【发布时间】: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<? extends T>) in the type CriteriaQuery<T> is not applicable for the arguments (Path<Object>)
。我应该如何改变它?我想得到一个类型为T
的对象,它只有ID
和VERSION
字段,而其他所有字段都是null
。
类型 T
扩展 AbstractEntity
具有这两个字段。
entityClazz
是T.class
。
【问题讨论】:
【参考方案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();
您可以在其中将“名字”更改为所需列的名称。
【讨论】:
以上是关于JPA & Criteria API - 仅选择特定列的主要内容,如果未能解决你的问题,请参考以下文章
如何在 JPA Criteria API 上正确使用 JOIN