Hibernate多次获取相关对象

时间:2016-05-07 16:07:02

标签: java hibernate

@Entity
@Table(name = "MATCHES")
public class Match implements Serializable{
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "MATCH_ID")
	private Long id;

	@ManyToMany(mappedBy = "matches", cascade = CascadeType.ALL)
	private Set<Team> teams = new HashSet<Team>();
}

@Entity
@Table(name = "Teams")
public class Team implements Serializable {
	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	@Column(name = "TEAM_ID")
	private long id;

	@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
	@JoinTable(name = "TEAM_MATCH", joinColumns = { @JoinColumn(name = "TEAM_ID") }, inverseJoinColumns = {
			@JoinColumn(name = "MATCH_ID") })
	private Set<Match> matches = new HashSet<Match>();
}

我得到了那些课程,现在我想得到所有的比赛,让我们说,打印两队的名字。

public List getAllMatches() {
		Session session = HibernateUtil.getSession();
		Transaction t = session.beginTransaction();
		Criteria criteria = session.createCriteria(Match.class, "match");
		criteria.createAlias("match.teams", "mt", JoinType.LEFT_OUTER_JOIN);
		List result = criteria.list();
		t.commit();
		session.close();
		return result;
	}

但是当我调用该方法时,当我在表中只有一个匹配时,结果的大小为2。结果中的两个比赛都有2支球队,这是正确的。我不知道为什么会这样。我想要的是在“团队”集中有一个Match对象和两个Team对象,但我有两个Match对象。他们很好,但有两个。我对此完全陌生,不知道如何解决这些问题。我尝试从Team中的@ManyToMany删除'FetchType.LAZY',但它不起作用。团队也有玩家/培训师等属性,他们在自己的桌子上,但我不想深入挖掘,婴儿步骤。我不知道如果做这样的查询是个好主意,我应该返回Matches然后如果我想获得团队,请在另一个会话中获取它们吗?

编辑:我添加criteria.setResultTransformer(DistinctRootEntityResultTransformer.INSTANCE);并且它有效,是我想要解决的问题,或者这是完全不同的事情,我很幸运?

1 个答案:

答案 0 :(得分:0)

我认为重复是您createAlias电话的结果,除此之外,这种副作用首先是多余的。

通过使用这些参数调用createAlias,您告诉Hibernate不仅返回所有匹配,而是首先使用TEAM_MATCH表对MATCHES表进行交叉索引,并为每对匹配的行返回结果。您可以在匹配表中获得一行结果,与第一个团队的多对多映射配对,匹配表中同一行的另一个结果与第二个团队的多对多映射配对。

我猜这个行的意图是告诉Hibernate获取关联。这不是必需的,Hibernate将在需要时自动获取相关对象。

只需删除criteria.createAlias来电,您应该得到预期的结果 - 但需要注意一点。因为关联是使用延迟提取,所以在您访问它之前,Hibernate不会加载它,如果在关闭会话后出现,则会得到LazyInitializationException。一般来说,我建议你更喜欢通过在更高的抽象级别打开和关闭会话来解决这个问题 - 让所有匹配大概是一些更大的任务的一部分,并且在大多数情况下你应该在整个期间使用一个会话任务除非涉及大量延迟(例如等待用户输入)。但是,改变这可能需要对代码进行重大的重新设计;快速解决方案是简单地遍历结果列表,并在每个Hibernate.initialize()的{​​{1}}集合上调用teams。或者您可以将获取类型更改为急切,如果始终加载关联的性能成本是否可以接受。