【问题标题】:How can I retrieve multiple objects with JPA?如何使用 JPA 检索多个对象?
【发布时间】:2011-06-06 21:17:45
【问题描述】:

我在这个数据模型中使用 JPA2/hibernate:

class Stock {
  @ManyToOne
  private StockGroup stockGroup;
  private boolean visible;
}
class StockGroup {
  @OneToMany(mappedBy = "stockGroup")
  private List<Stock> stocks;
}

我想检索 StockGroup 的包含 Stock 的 visible==true
我想出了这个错误的代码:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<StockGroup> q = cb.createQuery(StockGroup.class);
Root<StockGroup> r = q.from(StockGroup.class);
Join<StockGroup, Stock> j = r.join(StockGroup_.stocks, JoinType.INNER);
Predicate p = cb.equal(j.get(Stock_.visible), true);

// This becomes a cartesian product :(
List<StockGroup> l = em.createQuery(q.where(p)).getResultList();   
// Stocks are not filtered on visible :(
l.get(0).getStocks();

是否可以使用一个 CriteriaQuery 检索 StockGroup 和 Stock 对象,或者 JPA 一次只能填充一种类型?或者我可以在.getStocks() 被懒惰填充时添加一些标准吗?

【问题讨论】:

    标签: java hibernate orm jpa jpa-2.0


    【解决方案1】:

    这样做的诀窍是返回一个元组,其中包含 Stock 和 StockGroup 之间的老式连接,如下所示:

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Tuple> q = cb.createQuery(Tuple.class);
    Root<Stock> sRoot = q.from(Stock.class);
    Root<StockGroup> sgRoot = q.from(StockGroup.class);
    
    q.select(cb.tuple(sRoot, sgRoot)).where(
        cb.and(cb.equal(sRoot.get(Stock_.stockGroup), sgRoot),
            cb.isTrue(sRoot.get(Stock_.visible))));
    List<Tuple> l = em.createQuery(q).getResultList();
    

    然后元组不是完全类型安全的,但您可以通过位置(或通过别名,如果您为选择表达式或根指定别名)访问它:

    for (Tuple t : l) {
        Stock s = (Stock) t.get(0);
        StockGroup sg = (StockGroup) t.get(1);
    
        System.out.println("Stock is : " + s + "    .... StockGroup: " + sg);
    }
    

    有一个good article on IBM DeveloperWorks on JPA2 Typesafe Queries

    祝你在 JPA2 的努力中好运!

    【讨论】:

    • 如果害怕这个...手动连接、不安全的强制转换、冗长的语法和手动组合对象。也许我需要切换到 OpenJPA 或 Querydsl 之类的东西。但是,您仍然完美地回答了我的问题(我已阅读整篇文章)。如果您回答第二部分,您会得到奖励:如果我首先只检索 StockGroups,我可以在调用 .getStocks() 时添加一些标准吗?换句话说,我可以把代理对象弄乱吗?
    • 我认为 JPA 不支持这一点——没有这样的构造(过滤集合),因为你的对象中会得到一个不完整的集合。我也看不到 OpenJPA 将如何帮助您,而且我对 QueryDsl 的了解也不够多,无法提供建议。对不起!
    • 但是,您可以添加一些更高级别的方法/帮助程序来进行手动连接,例如 manualJoin(cb, sgRoot, sRoot, Stock_.group, cb.isTrue(sRoot.get(Stock_ .visible))),并可能相应地包装元组列表,作为某种创可贴?可惜他们没有制作 Tuple1、Tuple2 等。
    猜你喜欢
    • 2015-12-22
    • 1970-01-01
    • 1970-01-01
    • 2016-12-25
    • 1970-01-01
    • 2018-04-09
    • 1970-01-01
    • 2015-05-13
    • 1970-01-01
    相关资源
    最近更新 更多