EclipseLink JPA:我可以从一个构建器运行多个查询吗?

发布于 2024-12-03 03:59:30 字数 2529 浏览 1 评论 0原文

我有一个构建并运行条件查询的方法。该查询执行我想要的操作,特别是它根据用户输入过滤(和排序)记录。

此外,查询大小仅限于屏幕上的记录数。这很重要,因为数据表可能非常大。

但是,如果应用过滤器,我想计算在查询不受限制的情况下将返回的记录数。因此,这意味着运行两个查询:一个用于获取记录,另一个用于计算整个集合中的记录。它看起来像这样:

public List<Log> runQuery(TableQueryParameters tqp) {

    // get the builder, query, and root

    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Log> query = builder.createQuery(Log.class);
    Root<Log> root = query.from(Log.class); 

    // build the requested filters

    Predicate filter = null;
    for (TableQueryParameters.FilterTerm ft : tqp.getFilterTerms()) {

       // this section runs trough the user input and constructs the 
       // predicate

    }
    if (filter != null) query.where(filter);

    // attach the requested ordering

    List<Order> orders = new ArrayList<Order>();
    for (TableQueryParameters.SortTerm st : tqp.getActiveSortTerms()) {

        // this section constructs the Order objects

    }
    if (!orders.isEmpty()) query.orderBy(orders);        

    // run the query

    TypedQuery<Log> typedQuery = em.createQuery(query);
    typedQuery.setFirstResult((int) tqp.getStartRecord());
    typedQuery.setMaxResults(tqp.getPageSize());
    List<Log> list = typedQuery.getResultList();

    // if we need the result size, fetch it now

    if (tqp.isNeedResultSize()) {
        CriteriaQuery<Long> countQuery = builder.createQuery(Long.class);
        countQuery.select(builder.count(countQuery.from(Log.class)));
        if (filter != null) countQuery.where(filter);
        tqp.setResultSize(em.createQuery(countQuery).getSingleResult().intValue());
    }

    return list;
}

因此,我在同一个 CriteriaBuilder 上调用 createQuery 两次,并在它们之间共享 Predicate 对象(过滤器)。当我运行第二个查询时,我有时会收到以下消息:

异常 [EclipseLink-6089](Eclipse 持久性服务 - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.QueryException 异常 描述:表达式未正确初始化。仅有的 应将单个 ExpressionBuilder 用于查询。并联用 表达式,查询类必须提供给ExpressionBuilder 构造函数,并且查询的 ExpressionBuilder 必须始终位于 表达式的左侧。表达式:[ 基数 com.myqwip.database.Log] 查询:ReportQuery(referenceClass=Log ) at org.eclipse.persistence.exceptions.QueryException.noExpressionBuilderFound(QueryException.java:874) 在 org.eclipse.persistence.expressions.ExpressionBuilder.getDescriptor(ExpressionBuilder.java:195) 在 org.eclipse.persistence.internal.expressions.DataExpression.getMapping(DataExpression.java:214)

有人可以告诉我为什么这个错误间歇性地出现,以及我应该做什么来解决这个问题?

I have a method that builds and runs a Criteria query. The query does what I want it to, specifically it filters (and sorts) records based on user input.

Also, the query size is restricted to the number of records on the screen. This is important because the data table can be potentially very large.

However, if filters are applied, I want to count the number of records that would be returned if the query was not limited. So this means running two queries: one to fetch the records and then one to count the records that are in the overall set. It looks like this:

public List<Log> runQuery(TableQueryParameters tqp) {

    // get the builder, query, and root

    CriteriaBuilder builder = em.getCriteriaBuilder();
    CriteriaQuery<Log> query = builder.createQuery(Log.class);
    Root<Log> root = query.from(Log.class); 

    // build the requested filters

    Predicate filter = null;
    for (TableQueryParameters.FilterTerm ft : tqp.getFilterTerms()) {

       // this section runs trough the user input and constructs the 
       // predicate

    }
    if (filter != null) query.where(filter);

    // attach the requested ordering

    List<Order> orders = new ArrayList<Order>();
    for (TableQueryParameters.SortTerm st : tqp.getActiveSortTerms()) {

        // this section constructs the Order objects

    }
    if (!orders.isEmpty()) query.orderBy(orders);        

    // run the query

    TypedQuery<Log> typedQuery = em.createQuery(query);
    typedQuery.setFirstResult((int) tqp.getStartRecord());
    typedQuery.setMaxResults(tqp.getPageSize());
    List<Log> list = typedQuery.getResultList();

    // if we need the result size, fetch it now

    if (tqp.isNeedResultSize()) {
        CriteriaQuery<Long> countQuery = builder.createQuery(Long.class);
        countQuery.select(builder.count(countQuery.from(Log.class)));
        if (filter != null) countQuery.where(filter);
        tqp.setResultSize(em.createQuery(countQuery).getSingleResult().intValue());
    }

    return list;
}

As a result, I call createQuery twice on the same CriteriaBuilder and I share the Predicate object (filter) between both of them. When I run the second query, I sometimes get the following message:

Exception [EclipseLink-6089] (Eclipse Persistence Services -
2.2.0.v20110202-r8913):
org.eclipse.persistence.exceptions.QueryException Exception
Description: The expression has not been initialized correctly. Only
a single ExpressionBuilder should be used for a query. For parallel
expressions, the query class must be provided to the ExpressionBuilder
constructor, and the query's ExpressionBuilder must always be on the
left side of the expression. Expression: [ Base
com.myqwip.database.Log] Query: ReportQuery(referenceClass=Log ) at
org.eclipse.persistence.exceptions.QueryException.noExpressionBuilderFound(QueryException.java:874)
at
org.eclipse.persistence.expressions.ExpressionBuilder.getDescriptor(ExpressionBuilder.java:195)
at
org.eclipse.persistence.internal.expressions.DataExpression.getMapping(DataExpression.java:214)

Can someone tell me why this error shows up intermittently, and what I should do to fix this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

海之角 2024-12-10 03:59:30

对问题的简短回答:是的,可以,但只能按顺序进行。

在上面的方法中,您开始创建第一个查询,然后开始创建第二个查询,执行第二个查询,然后执行第一个查询。

我遇到了完全相同的问题。不知道为什么会断断续续的难受。

换句话说,您开始创建第一个查询,在完成之前,您开始创建并执行另一个查询。

Hibernate 不会抱怨,但 eclipselink 不喜欢它。

如果您只是从查询计数开始,执行它,然后创建并执行另一个查询(通过将其拆分为 2 个方法来完成),eclipselink 不会抱怨。

请参阅https://issues.jboss.org/browse/SEAMSECURITY-91

Short answer to the question : Yes you can, but only sequentially.

In the method above, you start creating the first query, then start creating the second, the execute the second, then execute the first.

I had the exact same problem. I don't know why it's intermittent tough.

I other words, you start creating your first query, and before having finished it, you start creating and executing another.

Hibernate doesn't complain but eclipselink doesn't like it.

If you just start by the query count, execute it, and then create and execute the other query (what you've done by splitting it in 2 methods), eclipselink won't complain.

see https://issues.jboss.org/browse/SEAMSECURITY-91

噩梦成真你也成魔 2024-12-10 03:59:30

看来这个帖子不会引起太多的反应,所以我会以我的解决方式来回答这个问题。

最终,我最终将 runQuery() 方法分为两个方法:用于获取记录的 runQuery() 和用于获取计数的 runQueryCount()没有排序参数的记录。每个方法都有自己的对 em.getCriteriaBuilder() 的调用。我不知道这对 EntityManager 有什么影响,但此后问题就没有出现了。

此外,具有这些方法的 DAO 对象曾经是@ApplicationScoped。它现在没有声明的范围,因此它现在是根据使用它的各种 @RequestScoped 和 @ConversationScoped bean 按需构建的。我不知道这是否对问题有任何影响,但因为它还没有出现,因为从现在开始我将使用它作为我的代码模式。欢迎提出建议。

It looks like this posting isn't going to draw much more response, so I will answer this in how I resolved it.

Ultimately I ended up breaking my runQuery() method into two methods: runQuery() that fetches the records and runQueryCount() that fetches the count of records without sort parameters. Each method has its own call to em.getCriteriaBuilder(). I have no idea what effect that has on the EntityManager, but the problem has not appeared since.

Also, the DAO object that has these methods used to be @ApplicationScoped. It now has no declared scope, so it is now constructed on demand from the various @RequestScoped and @ConversationScoped beans that use it. I don't know if this has any effect on the problem but since it has not appeared since I will use this as my code pattern from now on. Suggestions welcome.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文