Tho*_*mas 8 java hibernate jpa
我们对Hibernate 3.3有一个n + 1选择问题.
为简单起见,我将做一个简短的抽象例子.
假设我们有以下简单类:
class MainEntity {
@Id
public Long id; //we have a table generator create this id
@OneToOne ( mappedBy ="main" )
public SubEntity subEntity;
}
class SubEntity {
@Id
@Column( name = "mainId" ) //note that this is the same column as the join column below
public Long mainId; //in order to have the exact same id as the corresponding MainEntity
@OneToOne ( fetch = FetchType.LAZY )
@JoinColumn ( name = "mainId", insertable = false, updatable = false, nullable = false )
public MainEntity main; //this is used for navigation and queries (" ... subentity.main = :x")
}
Run Code Online (Sandbox Code Playgroud)
因此,您可以看到SubEntity与MainEntity两个属性表示的关系,其中mainId属性是负责管理关系/外键的属性.
这非常有效,完全符合我们的需求.
然而,有一个问题,急切地加载SubEntity与一起MainEntity.
假设我有一个返回集合的查询MainEntity.使用当前设置,Hibernate将发出n + 1个选择:查询本身+ n为每个选择SubEntity.
当然我可以join fetch在查询中添加一个,但我更喜欢Hibernate自动执行此操作.因此我尝试添加@Fetch( FetchMode.JOIN ),但这没有做任何事情.
我也有使用没有问题@Fetch( FetchMode.SUBSELECT ),应该减少SELECT语句2 -原来的查询和选择的子实体(至少这是上标注的另一个属性发生了什么@CollectionOfElements和@Fetch( FetchMode.SUBSELECT )).
所以问题是:我如何告诉Hibernate 自动加入fetch或使用单个select来急切加载子实体?我错过了什么吗?
提前致谢,
托马斯
PS:可能存在问题的一件事可能是mappedBy = "main"它没有引用实际的id列,但我无法将其更改为mappedBy = "id".
如果要在MainEntity和SubEntity之间共享主键,请使用PrimaryKeyJoinColumn和MapsId注释.
通过使用通过使用相同的主键PrimaryKeyJoinColumn将MainEntity表与SubEntity表连接来加载实体.它应解决n + 1问题.
该MapsId注解让Hibernate的标识,从我们的例子另一个相关的实体复制将复制SubEntity.mainEntity.id到SubEntity.id.
@Entity
public class MainEntity {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
@Column(name = "main_Id")
private Long id;
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private SubEntity subEntity ;
}
@Entity
public class SubEntity
{
@Id @Column(name="main_Id_FK") Long id;
@MapsId
@OneToOne
@JoinColumn(name = "main_Id_FK")
@PrimaryKeyJoinColumn
private MainEntity mainEntity;
}
Run Code Online (Sandbox Code Playgroud)
Hibernate参考文档: