(1+N) 通过 OnetoOne 关联进行选择
考虑以下模型:
@Entity
public class User {
@Id
@Column(name = "USER_ID")
private Long userId;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@OneToOne
@PrimaryKeyJoinColumn
private UserExt userExt;
... //getters and setters
}
@Entity
public class UserExt {
@Id
@Column(name="USER_ID")
private Long id;
private String cdpId;
private Date lastChanged;
... //getters and setters
}
执行时:
Query query = session.createQuery("from User");
List<User> list = query.list();
Hibernate 执行
Hibernate: select user0_.USER_ID as USER1_0_, user0_.FIRST_NAME as FIRST2_0_, user0_.LAST_NAME as LAST3_0_, user0_.EXT_USERNAME as EXT4_0_ from USER user0_
Hibernate: select userext0_.USER_ID as USER1_1_0_, userext0_.cdpId as cdpId1_0_, userext0_.lastChanged as lastChan3_1_0_ from USER_EXT userext0_ where userext0_.USER_ID=?
Hibernate: select userext0_.USER_ID as USER1_1_0_, userext0_.cdpId as cdpId1_0_, userext0_.lastChanged as lastChan3_1_0_ from USER_EXT userext0_ where userext0_.USER_ID=?
...
...
使用具有特定属性的查询有效(选择 u.firstName、u.userExt.cdpId)。
但是,由于我想要完整的用户实体(“来自用户”),hibernate 会为第一个结果行中的每个结果行生成一个选择。
我不明白,因为默认的获取策略应该是“懒惰”而不是“急切”。强制其为 LAZY 并不能解决问题。
Considering the following model:
@Entity
public class User {
@Id
@Column(name = "USER_ID")
private Long userId;
@Column(name = "FIRST_NAME")
private String firstName;
@Column(name = "LAST_NAME")
private String lastName;
@OneToOne
@PrimaryKeyJoinColumn
private UserExt userExt;
... //getters and setters
}
@Entity
public class UserExt {
@Id
@Column(name="USER_ID")
private Long id;
private String cdpId;
private Date lastChanged;
... //getters and setters
}
when executing :
Query query = session.createQuery("from User");
List<User> list = query.list();
Hibernate executes
Hibernate: select user0_.USER_ID as USER1_0_, user0_.FIRST_NAME as FIRST2_0_, user0_.LAST_NAME as LAST3_0_, user0_.EXT_USERNAME as EXT4_0_ from USER user0_
Hibernate: select userext0_.USER_ID as USER1_1_0_, userext0_.cdpId as cdpId1_0_, userext0_.lastChanged as lastChan3_1_0_ from USER_EXT userext0_ where userext0_.USER_ID=?
Hibernate: select userext0_.USER_ID as USER1_1_0_, userext0_.cdpId as cdpId1_0_, userext0_.lastChanged as lastChan3_1_0_ from USER_EXT userext0_ where userext0_.USER_ID=?
...
...
Using a query with specific properties works (select u.firstName, u.userExt.cdpId).
However since I want the full User Entity ("from User"), hibernate generates one select for each result row in the first.
I don't get it since the default fetch strategy should be LAZY not EAGER. Forcing it to LAZY didn't fix the problem.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
这里有两个问题阻止延迟加载:
OneToOne
的默认获取策略是EAGER
(请记住,LAZY
只是一个提示持久性提供者)。LAZY
只能在OneToOne
关联上工作。我测试了以下内容:
并确认简单的
from User
仅加载所有用户并且不执行 N 个额外查询,
UserExt
是延迟加载的。因此,如果关联是强制性的,请使用适当的映射:)如果是非强制性的,则必须:
join fetch
急切加载 UserExt 以避免 N 个后续选择(当然,这在某种程度上违背了单独的表)请注意,当您使用 Query 接口时,Hibernate >= 3.x 会忽略 Fetch 注释。在这种情况下,您需要明确地编写该内容。这是一个示例:
相关问题
参考
There are two problems preventing lazy loading here:
OneToOne
isEAGER
(and keep in mind thatLAZY
is just a hint to the persistence provider).LAZY
can only work on aOneToOne
association if the association is non-nullable (at least without using bytecode instrumentation).I tested the following:
And confirm that a simple
from User
only loads all the usersAnd doesn't perform N additional queries, the
UserExt
are loaded lazily.So, if you association is mandatory, use the appropriate mapping :) And if it is non-mandatory, you'll have to either:
join fetch
to avoid the N subsequent selects (of course, this somehow defeats the point of a separate table)Note that Hibernate >= 3.x ignores the Fetch annotation when you use the Query interface. In that case, you need to write that explicitly. this is an example:
Related questions
Reference
使用 -ToOne(例如 @ManyToOne 和 @OneToOne)时的默认获取策略是 fetch=FetchType.EAGER 而不是 fetch=FetchType.LAZY
但 Hibernate HQL 会覆盖默认的获取策略。如果您想仅使用一个查询来检索完全初始化的对象,则必须调用
Default fetching strategy when using -ToOne such as @ManyToOne and @OneToOne is fetch=FetchType.EAGER NOT fetch=FetchType.LAZY
But Hibernate HQL overrides default fetching strategy. If you want to retrieve a fully initialized object by using just one query you must call
使用可选= true 与像这样的一对一关系,以避免您自己的获取策略的n+1 问题。
use optional =true with a one-to-one relationship like this to avoid the n+1 issue with your own Fetch Strategy.