使用JPA一次加载和排序两个OneToMany关系

时间:2014-03-01 19:22:56

标签: java hibernate jpa

简而言之,我试图在网站上展示餐馆的菜单。一页(或URL,如果你喜欢)应该只显示一个菜单。餐厅/菜单在这一点上并不重要,但也许有助于使事情变得更加清晰。

主要实体:

  • Menu(“容器”)
  • Category(菜单有几个类别,如开胃菜,软饮料等。)
  • Item(一个类别包含作为项目的菜肴,饮料等)

enter image description here

如上所述,目的是一次性加载单个但整个菜单及其所有类别和类别的项目,或者至少使用少量查询(给定特定菜单ID)。在第一个天真的方法中,我使用了以下JPQL查询:

SELECT DISTINCT m FROM Menu m JOIN FETCH m.categories c JOIN FETCH c.items i WHERE m.id = :menuId

查询按预期工作,但还有另一项要求。正如您在上图中所看到的,类别和项目都有一个名为orderNo的属性(例如1,2,3,4 ......) - 此属性的唯一目的是控制类别和项目的顺序类别内部应该在网站上出现(当然开胃菜类别应该在主菜类别之前呈现,其次是甜点类别,简化术语。类别内的项目也是如此)。

这就是我目前的问题。选项:

  • 让数据库进行排序
  • 收到无序数据后,在我的应用程序中进行排序

我认为你会像我一样喜欢第一个选项,但它并不像我想的那么容易(好吧,它永远不会......)。我的实体的简化版本如下所示:

@Entity
public class Menu {
    // ...
    @OneToMany(mappedBy="menu")
    private Set<Category> categories;
}

@Entity
public class Category {
    // ...
    @ManyToOne
    private Menu menu;
    @OneToMany(mappedBy="category")
    private Set<Item> items;
}

@Entity
public class Item {
    // ...
    @ManyToOne
    private Category category;
}

我希望我可以用ORDER BY i.orderNo asc, c.orderNo asc之类的东西来扩展上面的JPQL查询,但这并非如此。然后我怀疑Set类型是一个问题,并用List替换了两个出现的问题。这导致MultipleBagFetchException(“无法同时获取多个行李”)。 我的意图(获得一个具有排序类别列表的实体,其中包含已排序项目列表)对JPA来说根本不可行吗?我的JPA提供商是Hibernate,但我可以在必要时进行更改。

编辑:

只是为了让您了解数据量:平均菜单有~7个类别,每个类别有~10个项目。 如果您认为我的整个模型需要改进,那么我会对其他方法持开放态度。

1 个答案:

答案 0 :(得分:1)

一个想法可能是使用@OneToMany反向映射和@OrderBy。

我认为您不需要该查询。以下内容可以加载给定ID的菜单

from Menu m where m.id = ID

该查询将获取您的菜单对象,并且所有反向映射将按@OrderBy注释的顺序填充