web-dev-qa-db-ja.com

"MultipleBagFetchException:3つの深さテーブルに参加するときに複数のバッグを同時に取得できません"

org.springFramework.Dao.InvalidDataAccessApiusageException:org.hibernate.loader.MultipleBagFetchException:複数のバッグを同時に取得することはできません:[order.Items、OrderItem.Options];

上記は、以下のような3つのテーブルに参加したときに直面した例外です。

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.getItems()。Get(0).getOptions.get(0)

どうやってその目標を達成できますか?

6
crazy_rudy

上記の例外を避けるためには、2つの可能性があります。

  1. 変更ListSet
    また
  2. Listを使用するが、2つの袋を取得しないでください。つまり、両方のコレクションでfetchJoin()を使用しないことを意味します。

フィルタリング:

条件コレクションがフィルタ処理されない場所を使用します。コレクションには、関連付けられているすべてのオブジェクトが含まれます。 JPAへの参加は、ルートオブジェクトの条件を作成するためのものです。 SQLと同じではありません。

JPA 2.1 JOIN ON機能を使用して関連付けられたコレクションをフィルタリングすることができます。これにより、ON節の追加条件が可能になります

参照 QueryDSL左結合は、on の追加条件を持ちます。

2
Peter Šály

本当にリストの代わりにSETを使用できない場合

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;
_

そして、e.g "Position"という名前の子テーブルに列を作成します

_ALTER TABLE child ADD COLUMN position integer NOT NULL default 0
_

また、表の他の列を使用できない場合は、リストを順番に照会する必要があります。または子のIDとカスタムゲッターを使用してください。

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

_public List<Child> getChilds() {
    childs.removeAll(Collections.singleton(null));
    return childs;
}
_
2
Gaspar