简体   繁体   English

JPA OneToOne惰性关系

[英]JPA OneToOne Lazy relation

I have 2 entities: User and UserProfile that have a bidirectional @OneToOne relationship between them. 我有2个实体: UserUserProfile ,它们之间具有双向@OneToOne关系。
Due to some old DB Design the UserProfile is the owner (i have the column user_id in users_profiles table) 由于某些旧的数据库设计,UserProfile是所有者(我在users_profiles表中有user_id列)
The relationship is Lazy as I have fetchType Lazy and optional = false. 因为我有fetchType Lazy和optional = false,所以关系是Lazy。
Everything works as expected, I mean when I load an UserProfile it does not automatically loads the User also. 一切都按预期工作,我的意思是当我加载UserProfile时,它也不会自动加载User。 I guess this is perfectly normal as I load from the owner side. 我猜这是完全正常的,因为我是从所有者方加载的。
My problem is that if I load a User (owned side) it loads automatically the UserProfile although the relationship is lazy. 我的问题是,如果我加载一个用户(拥有的一面),尽管关系是惰性的,但它会自动加载UserProfile。

I mean: Is this normal that when I load an entity from the owned side to load the owner entity also ? 我的意思是:这是正常的,当我从拥有方加载实体也加载所有者实体时吗?

@Entity
@Table(name = "users")
public class User extends BaseEntity implements Serializable {

    @OneToOne(mappedBy = "user", optional=false, fetch = FetchType.LAZY) 
    private UserProfile profile;
    // .................rest of entity 
 }




@Entity
@Table(name="users_profiles")
public class UserProfile extends BaseEntity implements Serializable {

    @OneToOne(optional=false, fetch = FetchType.LAZY)
    @JoinColumn(name="user_id")
    private User user;
    // ... rest of entity here 
}

The way that I test this is by loading the User entity with EntityManager method find(id). 我测试此方法的方式是通过使用EntityManager方法find(id)加载User实体。
I have noticed that when the relation is not lazy I have only one query with a join inside. 我注意到,当关系不是惰性时,我只有一个查询,里面有一个联接。 If I put the current setup I have two individual queries: 1 for user and the other one for profile. 如果我使用当前设置,则有两个查询:一个针对用户,另一个针对配置文件。

It is important to realize, that lazy loading behavior is not enforced by JPA specification, it is only recommended. 重要的是要意识到,延迟加载行为不是JPA规范所强制执行的,仅建议这样做。 It is up to hibernate as the implementation to choose if it is supported and under which conditions. 它是休眠的实现,以选择是否支持它以及在什么情况下进行选择。

Hibernate usually does its best to load the data lazily when requested, but in case of one-to-one mapping, when the relationship is stored in another table (the primary key is in table users_profiles ), it needs to query also the second table to retrieve the primary key to create a proxy object. Hibernate通常会在请求时尽其最大的努力来延迟加载数据,但是在one-to-one映射的情况下,当关系存储在另一个表中(主键在表users_profiles )时,它还需要查询第二个表检索主键以创建代理对象。 In fact, it does not retrieve only id, but full row and creates the UserProfile in eager way, because it costs almost nothing to fetch additinal data when the table needs to be joined in any case. 实际上,它不只检索id,而是检索全行,并以急切的方式创建UserProfile ,因为在任何情况下都需要连接表时,它几乎不需要花费任何费用来获取附加数据。

The answer for Hibernate: one-to-one lazy loading, optional = false suggests that making relationship non-optional should make it lazy, but I doubt it is true. Hibernate的答案:一对一的延迟加载,optional = false表示使关系成为非可选应该使它变得懒惰,但是我怀疑这是真的。 Hibernate would need to create a proxy without an ID, which is doubtfully correct in all cases. Hibernate需要创建一个没有ID的代理,这在所有情况下都是正确的。 One case where that would fail is when you remove the proxy object from the collection in parent entity, and then try to read its data - as the proxy itself does not carry enough information to retrieve data lazily, it is not possible without connection to parent entity. 一种失败的情况是,当您从父实体中的集合中删除代理对象,然后尝试读取其数据时-由于代理本身没有足够的信息来懒惰地检索数据,因此无法连接到父对象实体。

This is normal, by default, hibernate creates run-time proxies. 这是正常现象,默认情况下,休眠会创建运行时代理。 It loads the objects as a proxy unless a fetch mode is specified or set to false. 除非指定获取模式或将其设置为false,否则它将对象作为代理加载。 for example, load() always retrieves proxy objects. 例如,load()始终检索代理对象。 If called more than once within same session, it reads data from persistent context cache. 如果在同一会话中多次调用,它将从持久性上下文缓存中读取数据。 That's because once the object is loaded in cache, the next subsequent calls perform repeatable read. 这是因为一旦将对象加载到缓存中,接下来的后续调用将执行可重复读取。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM