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.EAGER
或Parent
删除AnotherParent
可以解决问题,但我需要它,所以真正的解决方案是使用@LazyCollection(LazyCollectionOption.FALSE)
代替FetchType
(谢谢到解决方案的Bozho。
答案 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)
评论Fetch
和LazyCollection
有时有助于运行项目。
@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。