【问题标题】:"MultipleBagFetchException: cannot simultaneously fetch multiple bags" when joining three depth table加入三个深度表时出现“MultipleBagFetchException:无法同时获取多个包”
【发布时间】:2019-03-24 16:53:35
【问题描述】:

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.loader.MultipleBagFetchException:不能同时 获取多个包:[Order.items, OrderItem.options];

上面是我在加入如下三个表时遇到的异常。

OrderItemOption.java

@Entity
public class OrderItemOption {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "item_option_id")
  private Long id;

  @Column(name = "item_id", nullable = false)
  private Long itemId;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(
      name = "item_id",
      referencedColumnName = "item_id",
      insertable = false,
      updatable = false
  )
  private OrderItem orderItem;
}

OrderItem.java

@Entity
public class OrderItem {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "item_id")
  private Long id;

  @Column(name = "order_id", nullable = false)
  private Long orderId;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(
      name = "order_id",
      referencedColumnName = "order_id",
      insertable = false,
      updatable = false,
      nullable = false
  )
  private Order order;

  @OneToMany(fetch = FetchType.LAZY, mappedBy = "orderItem")
  @OrderBy("item_option_id ASC")
  private List<OrderItemOption> options;
}

Order.java

@Entity
public class Order {
  @Id
  @Column(name = "order_id", nullable = false)
  private Long id;

  @OneToMany(fetch = FetchType.LAZY, mappedBy = "order")
  @OrderBy("item_id ASC")
  private List<OrderItem> items;
}

这是我一次加入他们的 QueryDSL 代码。

final QOrder order = QOrder.order;
final QOrderItem item = QOrderItem.orderItem;
final QOrderItemOption option = QOrderItemOption.orderItemOption;

from(order)
.leftJoin(order.items, item).fetchJoin()
.leftJoin(item.options, option).fetchJoin()
.where(
    order.id.eq(orderId)
        .and(item.id.in(itemIds))
        .and(option.id.in(optionIds))
)
.fetchOne())

我要做的是获取包含过滤关系的 Order 对象,以便我可以通过 order 对象访问过滤后的子项。 并且关系的类型应该是 List,而不是 Set。

例如 order.getItems().get(0).getOptions.get(0)

我怎样才能实现这个目标?

【问题讨论】:

    标签: java spring hibernate jpa querydsl


    【解决方案1】:

    为避免上述异常,有两种可能:

    1. List 更改为Set
    2. 使用List,但不要拿两个袋子。这意味着不要在两个集合上都使用 fetchJoin()

    过滤:

    使用 where 条件集合将不会被过滤。集合将包含所有关联的对象。加入 JPA 是为了在根对象 - 订单上创建条件。它与 SQL 中的不同。

    可以使用 JPA 2.1 JOIN ON 功能过滤关联的集合。这允许在ON 子句中添加附加条件

    例如见QueryDSL Left Join with additional conditions in ON

    【讨论】:

      【解决方案2】:

      如果实在不能用Set代替List:

      Parent.class

      @OneToMany(
          mappedBy = "parent",
          orphanRemoval = true,
          cascade = { CascadeType.PERSIST, CascadeType.MERGE }
      )
      @OrderColumn(name = "position")
      private List<Child> childs = new ArrayList<>();
      

      Child.class

      @ManyToOne(fetch = FetchType.LAZY)
      private Parent parent;
      

      并在 Child 的表中创建一个名为例如“位置”的列

      ALTER TABLE child ADD COLUMN position integer NOT NULL default 0
      

      如果不能使用表中的其他列,则需要按顺序查询列表。或者使用孩子的 id 和自定义 getter。

      @OrderColumn(name = "id_child", updatable = false, insertable = false)

      public List<Child> getChilds() {
          childs.removeAll(Collections.singleton(null));
          return childs;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-05-19
        • 1970-01-01
        • 1970-01-01
        • 2016-09-13
        • 2014-08-31
        • 2015-01-26
        • 2015-02-04
        • 2014-01-07
        相关资源
        最近更新 更多