简体   繁体   English

JPA / Hibernate:@ManyToOne和@OneToOne关系被标记为FetchType.LAZY,而Optional = false不能在em.find()上懒惰加载?

[英]JPA/Hibernate: @ManyToOne and @OneToOne relationships tagged as FetchType.LAZY and optional = false not loading lazily on em.find()?

I have the following entity (only relevant mappings shown): 我有以下实体(仅显示相关映射):

@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Integer id;

    @Column
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)                 // lazy XToOne
    @JoinColumn(name = "user_id", referencedColumnName = "person_id")
    private User user;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
    private Group group;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
    private Tendering tendering;

    ...
}

Note the comments above: there are three @XToOne relationships to other entities: 请注意上面的注释:与其他实体有三个@XToOne关系:

User (a SecurityIdentity sub class with a simple ID as PK, referenced by PQ representing the owner): 用户 (具有简单ID作为PK的SecurityIdentity子类,由PQ表示所有者):

@Entity
@Table(name = "Users")
@DiscriminatorValue(value = "user")
public class User extends SecurityIdentity
{
    @Column
    private String name;

    @OneToMany(mappedBy = "user")
    private Set<PQ> pqs = new HashSet<PQ>();

    ...
}

Group (also a SecurityIdentity sub class with a simple ID as PK, references the PQ to represent a set of users that can interact with that PQ): (也是具有简单ID作为PK的SecurityIdentity子类,引用PQ来表示可以与该PQ交互的一组用户):

@Entity
@Table(name = "Groups")
@DiscriminatorValue(value = "group")
public class Group extends SecurityIdentity
{
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pq_id", referencedColumnName = "id")
    private PQ pq;

    ...
}

Tendering : 招标

@Entity
@Table(name = "Tenderings")
public class Tendering implements Serializable
{
    @Id
    @Column(name = "pq_id", insertable = false, updatable = false)
    private Integer pqId;

    @Column(name = "external_code")
    private String externalCode;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pq_id", referencedColumnName = "id")
    private PQ pq;

    ...
}

Don't be confused about groups and users sharing IDs, just treat them as simple IDs. 不要对共享ID的组和用户感到困惑,只需将它们视为简单ID即可。 A tendering is just a separate document object (one-to-one). 招标只是一个单独的文档对象(一对一)。

As you can see there are three @XToOne relationships on the PQ entity, which, if no fetch type was set, would be loaded eagerly (JPA default). 正如您所看到的,PQ实体上有三个@XToOne关系,如果没有设置提取类型,则会急切加载(JPA默认值)。 So to prevent this I tagged all @XToOne relationships as FetchType.LAZY . 因此,为了防止这种情况,我将所有@XToOne关系标记为FetchType.LAZY

Now when using 现在使用时

em.find(PQ.class, someExistingId);

I get the Hibernate output: 我得到了Hibernate输出:

23:53:55,815 INFO  [stdout] Hibernate: select pq0_.id as id291_0_, pq0_.description as descript2_291_0_, pq0_.name as name291_0_, pq0_.submission_date as submission4_291_0_, pq0_.user_id as user5_291_0_ from PQs pq0_ where pq0_.id=?
23:53:55,818 INFO  [stdout] Hibernate: select user0_.id as id280_0_, user0_1_.identity_type_id as identity2_280_0_, user0_.is_enabled as is1_297_0_, user0_.name as name297_0_, user0_.password as password297_0_, user0_.person_id as person5_297_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
23:53:55,821 INFO  [stdout] Hibernate: select group0_.id as id280_0_, group0_1_.identity_type_id as identity2_280_0_, group0_.pq_id as pq2_281_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?
23:53:55,823 INFO  [stdout] Hibernate: select tendering0_.pq_id as pq1_296_0_, tendering0_.binary_file as binary2_296_0_, tendering0_.customer_id as customer6_296_0_, tendering0_.description as descript3_296_0_, tendering0_.external_code as external4_296_0_, tendering0_.title as title296_0_ from Tenderings tendering0_ where tendering0_.pq_id=?

The three extra SELECTs stem from the @XToOne relationships (as described in many places on the net). 另外三个SELECT来自@XToOne关系(如网上许多地方所述)。 The source I was looking at mostly is this: 我看到的来源主要是这样的:

Making a OneToOne-relation lazy 使OneToOne关系变得懒惰

As mentioned there, the @ManyToOne relationship User user shouldn't be fetched: 如前所述,不应提取@ManyToOne关系User user

@ManyToOne(fetch=FetchType.LAZY) should work just fine. @ManyToOne(fetch=FetchType.LAZY)应该可以正常工作。

... here the relationship from PQ to User , but it is fetched as you can see from the select user0_.id as id280_0_, ... statement... ...这里是从PQUser的关系,但是从select user0_.id as id280_0_, ...可以看到它 select user0_.id as id280_0_, ...语句...

For the other two Group group and Tendering tendering , both @OneToOne reverse mappings, the foreign keys reference the PQs table's PK (ID), resulting in the same mapping in the PQ entity. 对于另外两个Group group和Tendering Tendering tendering ,两个@OneToOne 反向映射,外键引用PQs表的PK(ID),导致PQ实体中的相同映射。

Note that all three relationships aren't optional: a PQ always has an owner (user), and a PQ is always referenced by a tendering and a group entity. 请注意,所有三个关系都不是可选的:PQ始终具有所有者(用户),并且PQ始终由招标和组实体引用。 I just hadn't modeled that in JPA above yet... 我刚才没有在上面的JPA中建模......

So, when adding optional = false to the three relationships of the PQ entity: 因此,在将PQ实体的三个关系中添加optional = false时:

@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Integer id;

    @Column
    private String name;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id", referencedColumnName = "person_id")
    private User user;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
    private Group group;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
    private Tendering tendering;

    ...
}

... I get the following Hibernate output: ...我得到以下Hibernate输出:

00:47:34,397 INFO  [stdout] Hibernate: select pq0_.id as id361_0_, pq0_.description as descript2_361_0_, pq0_.name as name361_0_, pq0_.submission_date as submission4_361_0_, pq0_.user_id as user5_361_0_ from PQs pq0_ where pq0_.id=?
00:47:34,410 INFO  [stdout] Hibernate: select user0_.id as id350_0_, user0_1_.identity_type_id as identity2_350_0_, user0_.is_enabled as is1_367_0_, user0_.name as name367_0_, user0_.password as password367_0_, user0_.person_id as person5_367_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
00:47:34,413 INFO  [stdout] Hibernate: select group0_.id as id350_0_, group0_1_.identity_type_id as identity2_350_0_, group0_.pq_id as pq2_351_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?

Note, that I've only been playing with the optional = false on the PQ entity, as this is the one I use in em.find(...) . 注意,我只在PQ实体上使用optional = false ,因为这是我在em.find(...)使用的em.find(...) (If this is not sufficient, please enlighten me.) (如果这还不够,请赐教。)

My question now is two-fold: 我现在的问题是双重的:

  1. Why is the @ManyToOne to the User entity fetched eagerly (given that is was said to be working lazily, see Making a OneToOne-relation lazy )? 为什么@ManyToOne急切地获取User实体(鉴于据说这是懒惰的工作,请参阅使一个OneToOne关系变得懒惰 )?
  2. Why is only the OneToOne relationship to the Tendering entity left off being fetched? 为什么只有OneToOneTendering实体的关系不被提取? Is it because the Tendering entity references the PQ's PK column as a PK itself ( @Id in Tendering ), which the Group entity doesn't (regular relationship to the PQ's PK)? 是因为Tendering实体将PQ的PK列引用为PK本身( Tendering @Id ),而Group实体没有(与PQ的PK有规律关系)?

What's wrong? 怎么了? How do I make these non-optional relationships lazy? 如何使这些非可选关系变得懒惰? (without code-instrumentation or other hacks, just plain annotations...) (没有代码检测或其他黑客,只是简单的注释......)

I know the LAZY thing is just a hint for the JPA provider to do something about lazy loading or not, but in this case it seems as if something else is wrong (as part of it is working). 我知道LAZY的事情只是提示JPA提供者做一些关于延迟加载的事情,但是在这种情况下,好像其他东西是错误的(因为它的一部分是有效的)。

PS: I'm using Hibernate 4.0 BETA, the version that comes with JBoss 7.0.0.Final along with JPA annotations only (the above are all JPA 1.0 compatible). PS:我正在使用Hibernate 4.0 BETA,JBoss 7.0.0.Final附带的版本以及JPA注释(以上都是JPA 1.0兼容)。

Hi I am not sure about JPA, but for many-to-one and one-to-one mappings the lazy values that are supported hibernate are proxy , no-proxy and false out of which false is defaulted. 嗨,我不确定JPA,但对于many-to-oneone-to-one映射,支持hibernate的惰性值是proxyno-proxyfalse ,其中false是默认的。 check this part of the DTD 检查DTD的这一部分

lazy="proxy|no-proxy|false"

and you can check this Link . 你可以查看这个链接 I think this answers your first question to an extend. 我认为这可以解决你的第一个问题。

there are differences between using hibernate annotations and jpa annotations and as far as i know, hibernate is lazy loaded by default except in some cases. 使用hibernate注释和jpa注释之间存在差异,据我所知,除了某些情况外,hibernate默认是延迟加载的。 here's a quick discussion: 这是一个快速讨论:

http://community.jboss.org/wiki/AShortPrimerOnFetchingStrategies http://community.jboss.org/wiki/AShortPrimerOnFetchingStrategies

Hi Kawu you show extra SELECTs because it will execute SELECTs for all involved entities, try using FetchType.LAZY for default One-to-Many and in most cases so using FETCH JOIN to get results. 嗨Kawu你显示额外的SELECT,因为它将为所有涉及的实体执行SELECTs,尝试使用FetchType.LAZY默认为一对多,在大多数情况下使用FETCH JOIN来获得结果。

I hope to help u or someone that need this information 我希望能帮助你或需要这些信息的人

* ToOne关系意味着在对象初始化之后必须有(代理)bean,一旦以任何方式访问它就会触发select(你看到它)你确定你对强制加载的对象什么都不做?

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

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