开发者

JPA 2: Change @NamedNativeQuery to CriteriaBuilder equivalent

Is it possible to change this @NamedQuery query:

SELECT @rownum:=@rownum+1 'no', m.title, m.author, REPLACE(SUBSTRING_INDEX(m.content, ' ', 20),开发者_开发问答 '<br>', ' '), m.viewed, m.hashid FROM book m, (SELECT @rownum:=0) r WHERE m.lang = ?1 AND m.title like CONCAT('%',?2,'%') ORDER BY m.title asc

to a CriteriaBuilder equivalent. Or not?...


I think the natural way to do this would be to handle the query in JPA, but to do the numbering and string mangling in Java. The query looks like this:

EntityManagerFactory emf;
String lang;
String keyword;

CriteriaBuilder builder = emf.getCriteriaBuilder();
final CriteriaQuery<Book> criteria = builder.createQuery(Book.class);
Root<Book> root = criteria.from(Book.class);
criteria.where(builder.and(builder.equal(root.get(Book_.lang), lang), builder.like(root.get(Book_.title), ("%" + keyword + "%"))));
criteria.orderBy(builder.asc(root.get(Book_.title)));

Since the results come back in a list, you can simply use the index into the list for the 'no' field, and you can write a method getContentSnippet() on Book to do the substringing and replacement.

If you really wanted to do the string mangling in the database, perhaps to reduce the amount of text transferred, then you could write a tuple query, which could retrieve the book and the snippet. Note that i would still retrieve the whole book, rather than individual fields, because this makes subsequent programming so much easier; if you want to avoid having the whole content transferred, mark it for lazy loading in the Book class. The query looks like:

CriteriaBuilder builder = emf.getCriteriaBuilder();
final CriteriaQuery<Tuple> criteria = builder.createTupleQuery();
final Root<Book> root = criteria.from(Book.class);
final Expression<String> snippetExpr = builder.substring(root.get(Book_.content), 1, 120);
criteria.multiselect(root, snippetExpr);
criteria.where(builder.and(builder.equal(root.get(Book_.lang), lang), builder.like(root.get(Book_.title), ("%" + keyword + "%"))));
criteria.orderBy(builder.asc(root.get(Book_.title)));

I'm using substring to build the snippet, because i'm using PostgreSQL, and that doesn't have an equivalent of the SUBSTRING_INDEX function. You could use CriteriaBuilder.function to call it with MySQL. I'm still not doing the numbering or replacement in the query, because i still think that's better done in code.

EntityManager em = emf.createEntityManager();
TypedQuery<Tuple> q = em.createQuery(criteria);
List<Tuple> booksAndSnippets = q.getResultList();
for (int i = 0; i < booksAndSnippets.size(); ++i) {
    Tuple bookAndSnippet = booksAndSnippets.get(i);
    int no = i + 1;
    Book book = bookAndSnippet.get(root);
    String snippet = bookAndSnippet.get(snippetExpr).replace("<br>", " ");
}

I really think you might have an easier time using JPQL, though!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜