Hibernate无法同时获取多个行李

时间:2010-12-02 12:28:20

标签: java hibernate jpa java-persistence-api

Hibernate在创建SessionFactory期间抛出此异常:

  

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

这是我的测试用例:

Parent.java

@Entity
public Parent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 // @IndexColumn(name="INDEX_COL") if I had this the problem solve but I retrieve more children than I have, one child is null.
 private List<Child> children;

}

Child.java

@Entity
public Child {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @ManyToOne
 private Parent parent;

}

这个问题怎么样?我该怎么办?


修改

好吧,我遇到的问题是另一个“父”实体在我父母的内部,我的真实行为是:

Parent.java

@Entity
public Parent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @ManyToOne
 private AntoherParent anotherParent;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 private List<Child> children;

}

AnotherParent.java

@Entity
public AntoherParent {

 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Long id;

 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 private List<AnotherChild> anotherChildren;

}

Hibernate不喜欢带有FetchType.EAGER的两个集合,但这似乎是一个错误,我没有做不寻常的事情......

FetchType.EAGERParent删除AnotherParent可以解决问题,但我需要它,所以真正的解决方案是使用@LazyCollection(LazyCollectionOption.FALSE)代替FetchType(谢谢到解决方案的Bozho

16 个答案:

答案 0 :(得分:470)

我认为更新版本的hibernate(支持JPA 2.0)应该可以解决这个问题。但是否则你可以通过使用:

注释集合字段来解决它
@LazyCollection(LazyCollectionOption.FALSE)

请务必从fetchType注释中删除@*ToMany属性。

但请注意,在大多数情况下,Set<Child>List<Child>更合适,因此,除非您确实需要List,否则请转到Set

答案 1 :(得分:263)

只需从List类型更改为Set类型。

答案 2 :(得分:113)

在代码中添加特定于Hibernate的@Fetch批注:

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

这应解决与Hibernate错误HHH-1718

相关的问题

答案 3 :(得分:23)

在尝试了这篇文章和其他文章中描述的每一个选项之后,我得出的结论是修复是如下。

在每个XToMany地方@ XXXToMany(mappedBy="parent", fetch=FetchType.EAGER)

之后
@Fetch(value = FetchMode.SUBSELECT)

这对我有用

答案 4 :(得分:18)

要解决此问题,只需使用Set代替List嵌套对象。

@OneToMany
Set<Your_object> objectList;

并且不要忘记使用fetch=FetchType.EAGER

它会起作用。

如果你想坚持使用列表,那么Hibernate还有一个概念CollectionId

答案 5 :(得分:11)

我在这种对象映射中发现了一篇关于Hibernate行为的博客文章:http://blog.eyallupu.com/2010/06/hibernate-exception-simultaneously.html

答案 6 :(得分:5)

您可以在JPA中保留展位EAGER列表,并在其中至少添加一个JPA注释 @OrderColumn (显然是要订购的字段的名称)。不需要特定的休眠注释。 但请记住,如果所选字段的值不是从0

开始,它可能会在列表中创建空元素
 [...]
 @OneToMany(mappedBy="parent", fetch=FetchType.EAGER)
 @OrderColumn(name="orderIndex")
 private List<Child> children;
 [...]

在儿童中你应该添加orderIndex字段

答案 7 :(得分:3)

之所以会出现这种异常,是因为Hibernate最终会生成对性能不利的笛卡尔乘积。

现在,尽管您可以使用Set而不是List来“解决”该问题,但是您不应该这样做,因为笛卡尔乘积仍将出现在基础SQL语句中。

最好从FetchType.EAGER切换到Fetchype.LAZY,因为热切获取是terrible idea that can lead to critical application performance issues

如果您需要在多层次结构中获取子实体,则最好从最里面的子实体到父实体as explained in this article中进行选择。

答案 8 :(得分:1)

当你有太多复杂的对象时,使用EAGER fetchType并不是一个好主意,最好使用LAZY,当你真的需要加载集合时,使用:Hibernate.initialize(parent.child)来获取数据。

答案 9 :(得分:1)

我们尝试设置而不是列表,这是一场噩梦:当您添加两个新对象时,等于()和 hashCode ()无法区分它们!因为他们没有任何身份证明。

像Eclipse这样的典型工具从数据库表中生成这种代码:

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

您还可以阅读this article,它正确解释了JPA / Hibernate的混乱程度。读完之后,我想这是我生命中最后一次使用ORM。

我也遇到过领域驱动设计人员,基本上说ORM是一件很糟糕的事情。

答案 10 :(得分:0)

对我来说,问题在于嵌套了 EAGER 获取。

一种解决方案是将嵌套字段设置为 LAZY 并使用Hibernate.initialize()加载嵌套字段:

x = session.get(ClassName.class, id);
Hibernate.initialize(x.getNestedField());

答案 11 :(得分:0)

最后,当我有多个FetchType.EAGER集合时,就会发生这种情况,

@ManyToMany(fetch = FetchType.EAGER, targetEntity = className.class)
@JoinColumn(name = "myClass_id")
@JsonView(SerializationView.Summary.class)
private Collection<Model> ModelObjects;

此外,这些集合都在同一列上。

为解决此问题,我将其中一个集合更改为FetchType.LAZY,因为这对于我的用例来说是可以的。

祝你好运! 〜J

答案 12 :(得分:0)

评论FetchLazyCollection有时有助于运行项目。

@Fetch(FetchMode.JOIN)
@LazyCollection(LazyCollectionOption.FALSE)

答案 13 :(得分:0)

关于int main() { cv::Mat in = cv::imread("C:/StackOverflow/Input/dtInput.png", cv::IMREAD_GRAYSCALE); std::vector<std::vector<cv::Point> > contours; cv::findContours(in.clone(), contours, cv::RETR_EXTERNAL, cv::CHAIN_APPROX_SIMPLE); if (contours.size() == 0) return 0; int cIndex = 0; for (int i = 1; i < contours.size(); ++i) { if (cv::contourArea(contours[i]) > cv::contourArea(contours[cIndex])) cIndex = i; } cv::Mat tmp = cv::Mat::zeros(in.size(), CV_8UC1); cv::drawContours(tmp, contours, cIndex, cv::Scalar::all(255), -1); cv::Mat dist; cv::distanceTransform(tmp, dist, CV_DIST_L2, 5); double minVal, maxVal; cv::Point minLoc, maxLoc; cv::minMaxLoc(dist, &minVal, &maxVal, &minLoc, &maxLoc); cv::Mat bgr; cv::cvtColor(in, bgr, cv::COLOR_GRAY2BGR); cv::circle(bgr, maxLoc, maxVal, cv::Scalar(0, 0, 255), 3); cv::imshow("dist", 1.0/255.0 *dist); cv::imshow("result", bgr); cv::imwrite("C:/StackOverflow/Input/dtInput_res.png", bgr); cv::imwrite("C:/StackOverflow/Input/dtInput_dt.png", dist); cv::waitKey(0); } 的一件好事是,即使在这种共存合法的情况下,带有此批注的多个字段也可以共存,而@LazyCollection(LazyCollectionOption.FALSE)无法并存。

例如,一个FetchType.EAGER可能有一个Order的列表(一个简短的列表)以及一个OrderGroup的列表(也很短)。 Promotions可以在两者上使用,而不会导致@LazyCollection(LazyCollectionOption.FALSE)都不LazyInitializationException

在我的情况下,MultipleBagFetchException确实解决了@Fetch的问题,但随后导致了臭名昭著的MultipleBacFetchException错误LazyInitializationException

答案 14 :(得分:0)

我通过注释解决了:

@OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY)

答案 15 :(得分:-4)

您可以使用新注释来解决此问题:

@XXXToXXX(targetEntity = XXXX.class, fetch = FetchType.LAZY)

实际上,fetch的默认值也是FetchType.LAZY。