【问题标题】:JPA 2 Criteria Fetch Path NavigationJPA 2 Criteria Fetch Path Navigation
【发布时间】:2010-12-22 16:36:27
【问题描述】:

使用 JPA 2 Criteria Join 方法,我可以执行以下操作:

    //Join Example (default inner join)
    int age = 25;
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Team> c = cb.createQuery(Team.class);
    Root<Team> t = c.from(Team.class);
    Join<Team, Player> p = t.join(Team_.players);
    c.select(t).where(cb.equal(p.get(Player_.age), age));
    TypedQuery<Team> q = entityManager.createQuery(c);
    List<Team> result = q.getResultList();

我怎样才能对 fetch 方法做同样的事情,我希望 Fetch 接口具有用于路径导航的 get 方法,但它没有:

    //Fetch Join Example

    int age = 25;
    CriteriaBuilder cb = entityManager.getCriteriaBuilder();
    CriteriaQuery<Team> cq = cb.createQuery(Team.class);
    Root<Team> t = cq.from(Team.class);
    Fetch<Team,Player> p = t.fetch(Team_.players);
    cq.where(cb.equal(p.get(Player_.age), age)); //This leads to compilation error there is no such method get in interface Fetch
    TypedQuery<Team> q = entityManager.createQuery(cq);
    List<Team> result = q.getResultList();

根据 Hiberante Documentation fetch 返回一个错误的 Join 对象。 http://docs.jboss.org/hibernate/stable/entitymanager/reference/en/html/querycriteria.html#querycriteria-from-fetch

【问题讨论】:

  • 我也有同样的问题?你找到一些解决方法了吗?

标签: java jpa jpa-2.0 fetch


【解决方案1】:

你所要做的就是:

1- 获取。 2- 然后,沿着路径走到你想要的地方。

在你的情况下:

int age = 25;
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Team> cq = cb.createQuery(Team.class);
Root<Team> t = cq.from(Team.class);
Fetch<Team,Player> p = t.fetch(Team_.players);
cq.where(cb.equal(t.get("player").get("age"), age)); 

【讨论】:

  • t.get("player") 不存在,因为 Team 实体只有 player 属性(在我们的示例中也是 Team_.players)。所以我会得到java.lang.IllegalArgumentException: Unable to resolve attribute [player] against path
【解决方案2】:

同意您对这种方法的看法,以及您希望它允许您所说的事实。另一种选择是

Join<Team, Player> p = t.join(Team_.players);
t.fetch(Team_.players);
c.select(t).where(cb.equal(p.get(Player_.age), age));

即做一个join(),为其添加一个fetch(),然后使用连接。这是不合逻辑的,只会增加 JPA 标准的不雅性,但无论如何,应该是一种解决方法

【讨论】:

  • 显然它可以工作,但它会导致多次加入: 休眠:从团队 team0_ 内部选择 ... .id 内部加入玩家 player2_ on team0_.id=players2_.team_id 内部加入 Person player2_1_ on player2_.id=players2_1_.id where player1_1_.age=25
  • 另请参阅blogs.sun.com/ldemichiel/entry/…,其中提到了问题。基本上是一个没有经过深思熟虑的 API
  • 当您使用mssql 执行order bydistinct(true) 时会中断
  • 正如 Alfredo 所说,这确实是双重连接。
  • 上面的blogs.sun.com链接已经完成,可以在回程机web.archive.org/web/20110820095223/http://blogs.oracle.com:80/…找到
【解决方案3】:

从 JPA 2.1 开始,动态实体图可用于在条件查询中获取,同时使用 join() 而不是 fetch()。从问题中的示例:

//Join Example (default inner join)
int age = 25;
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Team> c = cb.createQuery(Team.class);
Root<Team> t = c.from(Team.class);
Join<Team, Player> p = t.join(Team_.players);
c.select(t).where(cb.equal(p.get(Player_.age), age));
TypedQuery<Team> q = entityManager.createQuery(c);
List<Team> result = q.getResultList();

如果这样:

TypedQuery<Team> q = entityManager.createQuery(c);

替换为:

EntityGraph<Team> fetchGraph = getEntityManager().createEntityGraph(Team.class);
fetchGraph.addSubgraph(Team_.players);
TypedQuery<Team> q = entityManager.createQuery(c).setHint("javax.persistence.loadgraph", fetchGraph);

那么所有玩家都将被急切地获取。

【讨论】:

    【解决方案4】:

    我将 JPA 2.1 与 Hibernate 4.3.7 一起使用,以下对我很有效。它甚至看起来都不那么难看。

    Join<Team,Player> p = (Join) t.fetch(Team_.players);
    

    【讨论】:

      【解决方案5】:

      它适用于我使用 Hibernate Provider。

      //Join Example (default inner join)
      
          int age = 25;
          CriteriaBuilder cb = entityManager.getCriteriaBuilder();
          CriteriaQuery<Team> c = cb.createQuery(Team.class);
          Root<Team> t = c.from(Team.class);
      
          // Join<Team, Player> p = t.join(Team_.players); 
          Join<Team, Player> p = (Join<Team, Player>)t.fetch(Team_.players); 
      
          c.select(t).where(cb.equal(p.get(Player_.age), age));
          TypedQuery<Team> q = entityManager.createQuery(c);
          List<Team> result = q.getResultList();
      

      当然,它可能会破坏可移植性,但在我们的例子中,我们一直在使用其他 hibernate 的专有功能。

      *这很奇怪,因为hibernate文档没有显示这个例子。

      要掌握它,请查看此界面。

      /*
       * Hibernate, Relational Persistence for Idiomatic Java
       *
       * Copyright (c) 2010, Red Hat Inc. or third-party contributors as
       * indicated by the @author tags or express copyright attribution
       * statements applied by the authors.  All third-party contributions are
       * distributed under license by Red Hat Inc.
       *
       * This copyrighted material is made available to anyone wishing to use, modify,
       * copy, or redistribute it subject to the terms and conditions of the GNU
       * Lesser General Public License, as published by the Free Software Foundation.
       *
       * This program is distributed in the hope that it will be useful,
       * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
       * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
       * for more details.
       *
       * You should have received a copy of the GNU Lesser General Public License
       * along with this distribution; if not, write to:
       * Free Software Foundation, Inc.
       * 51 Franklin Street, Fifth Floor
       * Boston, MA  02110-1301  USA
       */
      package org.hibernate.ejb.criteria;
      
      import javax.persistence.criteria.Fetch;
      import javax.persistence.criteria.Join;
      
      /**
       * Consolidates the {@link Join} and {@link Fetch} hierarchies since that is how we implement them.
       * This allows us to treat them polymorphically.
      *
      * @author Steve Ebersole
      */
      public interface JoinImplementor<Z,X> extends Join<Z,X>, Fetch<Z,X>, FromImplementor<Z,X> {
          /**
           * {@inheritDoc}
           * <p/>
           * Refined return type
           */
          public JoinImplementor<Z,X> correlateTo(CriteriaSubqueryImpl subquery);
      }
      

      【讨论】:

      • 不错。正如您所说,这可能会使其无法在其他 JPA 供应商之间移植。
      • 使用 WAS v8.0 的 OpenJPA 2.1.2-SNAPSHOT 对我不起作用。 :-(
      • 这个演员表不起作用。您使用的是哪个 Hibernate 版本?
      • 在这种特殊情况下,我使用的是:hibernate 3.6.9.Final,我将使用新版本对其进行测试并在此处发表评论。你用的是什么版本的@amgohan?
      • 效果很好,但是在获取第二级(子表)中的字段时我有空指针,所以我必须对字段使用字符串名称而不是元模型中的名称,¿有同样问题的人吗?
      【解决方案6】:

      丑但是:

      Join<Team, Player> p=t.fetch(Team_.players);
      

      将在 sql 中使用 fetch 生成单连接 但是是一个丑陋的 hack,适用于 JBoss6.1 休眠

      【讨论】:

        【解决方案7】:

        我将 Hibernate 版本更新为“5.6.5.Final”,我认为问题已解决。

        【讨论】:

          猜你喜欢
          • 2016-12-22
          • 1970-01-01
          • 1970-01-01
          • 2016-10-31
          • 2011-03-29
          • 2017-03-15
          • 2021-02-24
          • 1970-01-01
          • 2012-09-07
          相关资源
          最近更新 更多