我已经将一个1:N关系Map到一个@OneToMany列表,但是当我访问这个列表时,由于一个OUTER JOIN,结果是重复的。
@Entity
public class Programmer
@ElementCollection(fetch=FetchType.EAGER)
@CollectionTable(name="emails", joinColumns=@JoinColumn(name="id", nullable=false))
@Column(name="email", nullable=false)
protected Set<String> emails = new HashSet<String>();
@OneToMany(mappedBy="programmer", fetch=FetchType.EAGER)
private List <Game> games = new ArrayList<Game>();
当我使用prog.getGames()获取属性时,结果会重复,因为Hibernate SQL进行了一个OUTER JOIN:
from programmer
left outer join emails on programmer.id=emails.id
left outer join game on programmer.id=game.id
where programmer.id=?
有没有不把列表转换成集合的解决方案?我需要用prog.getGames()获取游戏,不能使用自定义的HQL或标准。
3条答案
按热度按时间6vl6ewon1#
虽然
Set<>
的使用从根本上解决了您的问题,但我认为这只是一个创可贴,以获得您所追求的预期结果,但它在技术上并没有解决根本问题。您最终应该使用默认的延迟获取策略,因为我认为急切地加载任何关联,特别是基于集合的关联,都是特定于查询的,因此应该在您构造特定查询时切换,而不应作为实体Map模型的一部分受到影响。
考虑一下将来你添加一个新的查询,但是你只对聚合根实体的属性感兴趣。你的Map模型仍然会强制急切地获取这些关联,你会消耗额外的资源,因为有一个更大的持久性上下文,这意味着更多的内存消耗,并对你不打算使用的东西强制不必要的数据库连接。
如果有多个集合需要水合,我建议您考虑使用
FetchMode.SUBSELECT
代替。如果我们假设您的查询返回10个实体,则具有2个集合的默认惰性策略将发出21个查询(1个用于基本结果集,2个用于每个加载的实体)。
SUBSELECT
的好处是Hibernate实际上只会发出3个查询(1个用于基本结果集,1个用于每个集合,以加载所有实体的所有集合元素)。显然,根据特定的查询,将一个带有左连接的查询分解为3个查询实际上在数据库级别也可以执行得更好。qij5mzcb2#
我已经用
@Fetch(FetchMode.SUBSELECT)
解决了这个问题sycxhyv73#
我遇到了同样的问题。
companyUserRelations
有重复的对象(我的意思是指向同一对象的相同指针,而不是重复的数据)所以在阅读@dimitry response之后,我添加了
@Fetch(FetchMode.SUBSELECT)
,它工作了