org.hibernate.loader.MultipleBagFetchException:无法同时获取多个行李

时间:2014-07-10 11:26:37

标签: java hibernate jpa hibernate-mapping bag

以下是我的代码在这里,我使用多个列表从数据库中获取数据。 从hql查询中获取数据时,它显示异常。

Pojo Class

public class BillDetails implements java.io.Serializable {

private Long billNo;
// other fields
@LazyCollection(LazyCollectionOption.FALSE)
private List<BillPaidDetails> billPaidDetailses = new ArrayList<BillPaidDetails>();
private Set productReplacements = new HashSet(0);
@LazyCollection(LazyCollectionOption.FALSE)
private List<BillProduct> billProductList = new ArrayList<BillProduct>();
//getter and setter
}

hmb.xml文件

<class name="iland.hbm.BillDetails" table="bill_details" catalog="retail_shop">
        <id name="billNo" type="java.lang.Long">
            <column name="bill_no" />
            <generator class="identity" />
        </id>
 <bag name="billProductList" table="bill_product" inverse="true" lazy="false" fetch="join">
            <key>
                <column name="bill_no" not-null="true" />
            </key>
            <one-to-many class="iland.hbm.BillProduct" />
        </bag>
        <bag name="billPaidDetailses" table="bill_paid_details" inverse="true" lazy="false" fetch="select">
            <key>
                <column name="bill_no" not-null="true" />
            </key>
            <one-to-many class="iland.hbm.BillPaidDetails" />
        </bag>
        <set name="productReplacements" table="product_replacement" inverse="true" lazy="false" fetch="join">
            <key>
                <column name="bill_no" not-null="true" />
            </key>
            <one-to-many class="iland.hbm.ProductReplacement" />
        </set>
    </class>

Hql查询

String hql = "select distinct bd,sum(bpds.amount) from BillDetails as bd "
                    + "left join fetch bd.customerDetails as cd "
                    + "left join fetch bd.billProductList as bpd "
                    + "left join fetch bpd.product as pd "
                    +"left join fetch bd.billPaidDetailses as bpds "
                    + "where bd.billNo=:id "
                    + "and bd.client.id=:cid ";

我正在尝试跟踪查询以从数据库中获取数据,但这是显示的 org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags 如何解决这个问题

7 个答案:

答案 0 :(得分:20)

对我来说,我有同样的错误,我通过添加hibernate的注释解决了 的 @Fetch

@OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
@Fetch(value = FetchMode.SUBSELECT)
private List<Child> childs;

答案 1 :(得分:19)

正如this article中所述,Hibernate不允许提取多个包,因为这会生成Cartesian product

您可以将行李更改为设置,并添加order-by="id"属性以模拟&#39;有序列表行为:

private Set<BillPaidDetails> billPaidDetailses = new LinkedHashSet<>();
private Set<BillProduct> billProductList = new LinkedHashSet<>();

<set name="billProductList" table="bill_product" 
     inverse="true" lazy="false" fetch="join" order-by="id">
    <key>
        <column name="bill_no" not-null="true" />
    </key>
    <one-to-many class="iland.hbm.BillProduct" />
</set>

<set name="billPaidDetailses" table="bill_paid_details" 
     inverse="true" lazy="false" fetch="select" order-by="id">
    <key>
        <column name="bill_no" not-null="true" />
    </key>
    <one-to-many class="iland.hbm.BillPaidDetails" />
</set>

但仅仅因为你可以,这并不意味着你应该这样做。

您可以做的是在原始SQL查询中最多获取一个集合,而之后使用辅助查询获取其他集合。这样就可以避免笛卡尔积。

另一种选择是使用multi-level fetching from child up to parent entities

答案 2 :(得分:2)

您只能为实体(billPaidDetailsesbillProductList)的一个关系加入 - 获取。

在需要时考虑使用延迟关联和加载集合,或者使用惰性关联并使用Hibernate.initialize(..)手动加载集合。至少那是我得到similar issue后得出的结论。

无论哪种方式,它都会对数据库进行多次查询。

答案 3 :(得分:2)

更改为Set是最佳解决方案。但是,如果您不能用List替换Set(就像在我的情况下,大量使用特定于Lists的JSF标记),并且如果您可以使用Hibernate专有注释,您可以指定@IndexColumn (name = "INDEX_COL")。该解决方案对我来说效果更好,更改为Set将需要大量的重构。

所以,你的代码是这样的:

@IndexColumn (name = "INDEX_COL")
private List<BillPaidDetails> billPaidDetailses = new ArrayList<BillPaidDetails>();

@IndexColumn (name = "INDEX_COL")
private List<BillProduct> billProductList = new ArrayList<BillProduct>();

正如Igor在评论中建议的那样,您还可以创建代理方法来返回列表。我没有尝试过,但如果你不能使用Hibernate专有注释,那将是一个不错的选择。

答案 4 :(得分:0)

我使用了新的注释@OrderColumn而不是@IndexColumn(已弃用,请参见:https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/annotations/IndexColumn.html),并且现在可以使用。

使用@OrderColumn注释集合之一 例如

@ManyToMany(cascade = CascadeType.ALL)
@OrderColumn
private List<AddressEntity> addresses = Lists.newArrayList();

@Builder.Default
@ManyToMany(cascade = CascadeType.ALL)
private List<BankAccountEntity> bankAccounts = Lists.newArrayList();

答案 5 :(得分:0)

我发现在实体中使用@PostLoad带注释的方法最有用,我会做类似

的操作
@PostLoad
public void loadCollections(){
     int s1 = productReplacements.size();
     int s2 = billProductList.size();
}

这样,我可以很好地控制在加载实体的同一事务中对集合的急切加载和初始化。

答案 6 :(得分:-1)

您的请求获取的数据太多而HIbernate无法加载所有数据。 减少您的请求和/或配置您的实体以检索所需的数据