【发布时间】:2014-01-09 01:35:54
【问题描述】:
我有实体Post:
@Entity
@Table(name = "post")
@NamedQueries({
@NamedQuery(name = "getNewestPosts", query = "SELECT p FROM Post p ORDER BY p.date DESC"), // getting resultList ordered by date
@NamedQuery(name = "getMostVisitedPosts", query = "SELECT p FROM Post p ORDER BY p.visitors DESC"), // ordered by most visited
@NamedQuery(name = "getMostCommentedPosts", query = "SELECT p FROM Post p ORDER BY SIZE(p.comments) DESC")
})
public class Post implements Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "post_id", unique = true, nullable = false)
private Integer id;
@Column(name = "post_title", length=300, unique = false, nullable = false)
private String title;
@Column(name = "post_date", unique = false, nullable = false)
private Date date;
@Column(name = "post_summary", length=1000, unique = false, nullable = true)
private String summary;
@Column(name = "post_content", length=50000, unique = false, nullable = false)
private String content;
@Column(name = "post_visitors", unique = false, nullable = false)
private Integer visitors;
@ManyToOne
@JoinColumn (name = "user_id", referencedColumnName="user_id", nullable = false)
private User user;
@ManyToOne
@JoinColumn (name = "category_id", referencedColumnName="category_id", nullable = false)
private Category category;
@OneToMany(cascade = { ALL }, fetch = EAGER, mappedBy = "post")
private Set<Comment> comments = new HashSet<Comment>();
...
实体Comment:
@Entity
@Table(name = "comment")
public class Comment implements Serializable {
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "comment_id", unique = true, nullable = false)
private Integer id;
@Column(name = "comment_title", length=300, unique = false, nullable = false)
private String title;
@Column(name = "comment_date", unique = false, nullable = false)
private Date date;
@Column(name = "comment_content", length=600, unique = false, nullable = false)
private String content;
@ManyToOne
@JoinColumn (name = "user_id", referencedColumnName="user_id", nullable = false)
private User user;
@ManyToOne
@JoinColumn (name = "post_id", referencedColumnName="post_id", nullable = false)
private Post post;
...
那么,PostDAOBean 中的方法如下:
public List<Post> getMostCommentedPosts(int page, int postsPerPage){
Query q = em.createNamedQuery("getMostCommentedPosts");
q.setFirstResult(page - 1);
q.setMaxResults(postsPerPage);
List<Post> resultList = (List<Post>) q.getResultList();
if (resultList.isEmpty())
return null;
else
return resultList;
}
当我在 servlet 中调用此方法时,我得到下一个异常:
[07.01.2014 09:06] Class name: class mbs2.blog.server.session.PostDAOBean, method name: public java.util.List mbs2.blog.server.session.PostDAOBean.getMostCommentedPosts(int,int) started
[07.01.2014 09:06] Class name: class mbs2.blog.server.session.PostDAOBean, method name: public java.util.List mbs2.blog.server.session.PostDAOBean.getMostCommentedPosts(int,int)<openjpa-2.2.0-r422266:1244990 nonfatal user error> org.apache.openjpa.persistence.ArgumentException: "Encountered "SIZE" at character 31, but expected: ["AVG", "COUNT", "KEY", "MAX", "MIN", "SUM", "VALUE", <IDENTIFIER>]." while parsing JPQL "SELECT p FROM Post p ORDER BY SIZE(p.comments) DESC". See nested stack trace for original parse error.
at org.apache.openjpa.kernel.jpql.JPQLParser.parse(JPQLParser.java:51)
at org.apache.openjpa.kernel.ExpressionStoreQuery.newCompilation(ExpressionStoreQuery.java:154)
at org.apache.openjpa.kernel.QueryImpl.newCompilation(QueryImpl.java:672)
at org.apache.openjpa.kernel.QueryImpl.compilationFromCache(QueryImpl.java:654)
at org.apache.openjpa.kernel.QueryImpl.compileForCompilation(QueryImpl.java:620)
at org.apache.openjpa.kernel.QueryImpl.compileForExecutor(QueryImpl.java:682)
at org.apache.openjpa.kernel.QueryImpl.compile(QueryImpl.java:589)
at org.apache.openjpa.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:1038)
at org.apache.openjpa.persistence.EntityManagerImpl.createNamedQuery(EntityManagerImpl.java:102)
at org.apache.openejb.persistence.JtaEntityManager.createNamedQuery(JtaEntityManager.java:274)
at mbs2.blog.server.session.PostDAOBean.getMostCommentedPosts(PostDAOBean.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
...
您可以看到命名查询是:SELECT p FROM Post p ORDER BY SIZE(p.comments) DESC。
异常的原因是什么?
编辑
好的,我看到函数 SIZE(p.comments) 不能在 JPQL 中使用以由它订购。
使用 JPQL 获取相同数据的替代方法是什么?正确的 JPQL 查询?
编辑 尝试使用 JPA Criteria API 实现此查询:
public List<Post> getMostCommentedPosts(int page, int postsPerPage){
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Post> cq = cb.createQuery(Post.class);
Root<Post> p = cq.from(Post.class);
cq.select(p);
cq.orderBy(cb.desc(???));
...???...
}
在 JPA Criteria API 方面需要帮助。
【问题讨论】:
-
我不认为您可以在 SQL 中将聚合放在
ORDER BY中。不过可能是错的。 -
@CodeChimp hm,其他两个命名查询也使用
ORDER BY,并且它们对应的方法有效 -
看到异常,据说 jpa 支持 ["AVG", "COUNT", "KEY", "MAX", "MIN", "SUM", "VALUE",
]。而你使用 SIZE 函数 -
啊,我明白了问题...没有 SIZE 聚合函数。它在错误文本中。
-
@CodeChimp 我应该如何修改 JPQL 查询以获取按其 cmets 数量排序的所有帖子?感谢任何帮助