如何通过 hql 延迟加载一对一组合

发布于 2024-07-23 05:43:25 字数 1347 浏览 8 评论 0原文

如果实体 A 与实体 B 具有双向一或零到一映射。

映射如下:

<class name="EntityA" table="TABLE_A" mutable="true" lazy="true">
    <id name="idA" type="long" column="pk_a" unsaved-value="null">
        <generator class="sequence">
            <param name="sequence">pk_a_seq</param>
        </generator>
    </id>
    <one-to-one name="propertyB" class="EntityB" property-ref="propertyA" constrained="true" outer-join="false"/>
</class>

<class name="EntityB" table="TABLE_B" mutable="true" lazy="true">
    <id name="idB" type="long" column="pk_b" unsaved-value="null">
        <generator class="sequence">
            <param name="sequence">pk_b_seq</param>
        </generator>
    </id>
    <many-to-one name="propertyA" class="EntityA" not-null="true" unique="true" lazy="proxy" column="fk_a"/>
</class>

我为 EntityA 执行 hql 查询(或者更确切地说,命名 hql 查询)时,hibernate 急切地加载EntityA#propertyB 具有单独的 select 语句。

我的问题是,如果我的 hql 返回 1000 个 EntityA(所有实体都有各自的 EntityB),hibernate 将执行 n+1 个查询(第一个查询将针对 EntityA 返回 1000 个结果,而 n 个查询将来自 EntityA# propertyB选择延迟加载)。

但是,我不需要那些 EntityA#propertyB,这就是为什么我想延迟加载它们(而不让 hibernate 使用单独的 sql 查询)。

那可能吗? 如果是的话,我该怎么做?

谢谢, 弗朗兹

If have an entity A with a bidirectional one-or-zero-to-one mapping with entity B.

The mapping is as follows:

<class name="EntityA" table="TABLE_A" mutable="true" lazy="true">
    <id name="idA" type="long" column="pk_a" unsaved-value="null">
        <generator class="sequence">
            <param name="sequence">pk_a_seq</param>
        </generator>
    </id>
    <one-to-one name="propertyB" class="EntityB" property-ref="propertyA" constrained="true" outer-join="false"/>
</class>

and

<class name="EntityB" table="TABLE_B" mutable="true" lazy="true">
    <id name="idB" type="long" column="pk_b" unsaved-value="null">
        <generator class="sequence">
            <param name="sequence">pk_b_seq</param>
        </generator>
    </id>
    <many-to-one name="propertyA" class="EntityA" not-null="true" unique="true" lazy="proxy" column="fk_a"/>
</class>

When I do an hql query (or rather, a named hql query) for EntityA, hibernate eagerly loads EntityA#propertyB with a separate select statement.

My problem with that is if my hql returns 1000 EntityA's (with all having their own respective EntityB's), hibernate will do n+1 queries (1st query would be for EntityA returning 1000 results, while the n queries would be coming from the EntityA#propertyB select lazy loading).

However, I do not need those EntityA#propertyB's that's why I want to lazy load them instead (without having hibernate use a separate sql query).

Is that possible? And if it is, how do I do that?

Thanks,
Franz

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

℡Ms空城旧梦 2024-07-30 05:43:25

我已经解决了这个问题。

我所做的是将字段 EntityA#propertyB 转换为名称为 EntityA#propertyBs 的 Set。 但我保留了 EntityA#getPropertyB() 和 EntityA#setPropertyB(EntityB propertyB) 访问器方法。

这些访问器方法的方法体现在如下所示:

public EntityB getPropertyB() {
    return CollectionUtils.get(propertyBs, 0);
}

public void setPropertyBs(EntityB propertyB) {
    propertyBs= Collections.singleton(propertyB);
}

然后在我的映射中,我映射了集合 EntityA#propertyBs 并指定对“field”的访问。

<set name="scheduledAdInfos" lazy="true" fetch="subselect" access="field" cascade="none" inverse="true">
    <key column="pk_a"/>
    <one-to-many class="EntityB"/>
</set>

通过此设置,您现在可以创建从拥有的 POJO (EntityA) 到拥有的 POJO (EntityB) 的惰性映射,即使 TABLE_A 由 TABLE_B 拥有。

I've fixed this problem.

What I did was to create turn the field EntityA#propertyB into a Set with the name EntityA#propertyBs. But I retained the EntityA#getPropertyB() and EntityA#setPropertyB(EntityB propertyB) accessor methods.

The method bodies of those accessor methods are now something like this:

public EntityB getPropertyB() {
    return CollectionUtils.get(propertyBs, 0);
}

public void setPropertyBs(EntityB propertyB) {
    propertyBs= Collections.singleton(propertyB);
}

Then in my mapping, I mapped the set EntityA#propertyBs and specify the access to 'field'.

<set name="scheduledAdInfos" lazy="true" fetch="subselect" access="field" cascade="none" inverse="true">
    <key column="pk_a"/>
    <one-to-many class="EntityB"/>
</set>

With this setup, you can now create a lazy mapping from the owning POJO (EntityA) to the owned POJO (EntityB) even if TABLE_A is owned by TABLE_B.

海夕 2024-07-30 05:43:25

简短的回答:不,你不能这样做,至少在不更改数据库和映射的情况下不能这样做。 您基本上必须反转一对一映射和外键关系才能按照您想要的方式工作。


更长的答案:
Hibernate 可以延迟加载关联。 它执行此操作的方法是注入一个保存引用对象 ID 的代理对象。

在您的情况下,映射使得外键列位于 TABLE_B 中,即您使用多对一映射的位置。 因此,如果加载 B,hibernate 会在 fk_a 列中找到 FK 引用,并可以创建一个保存该值的代理。 当访问代理时,会加载相应的实体。

如果从表 A 中选择一条记录怎么办? Hibenate 将创建一个 A 对象,但为了能够填充 propertyB,它必须查找 TABLE_B,以找到 fk_a=a.id 对应的行。 Hibernate 没有其他方法可以找出延迟加载时要加载的记录。

实际上,这对 Hibernate 来说是一个改进,因为它还应该能够在延迟加载时加载其他唯一键,但当前的实现不允许这样做,也许你可以提出一个问题。

Short answer: No you cannot do that, at least not without changing the database and the mapping. You basically have to reverse the one-to-one mapping and the foreign key relation to work in the way you want.


Longer answer:
Hibernate can lazy load associations. The way it does this is by injecting a proxy object that holds the ID of the referenced object.

In your case, the mapping is such that the foreign-key column is in TABLE_B, that is, where you use the many-to-one mapping. So if you load a B, hibernate finds the FK reference in the fk_a column and can create a proxy that holds this value. When the proxy is accessed the corresponding entity is loaded.

What if a record from table A is selected? Hibenate will create an A object, but to be able to fill the propertyB, it will have to look into the TABLE_B, to find the corresponding row with fk_a=a.id. There is no other way for Hibernate to find out what record to load at lazy loading time.

Actually, this would be an improvement for Hibernate, since it should also be able to do the loading on other unique keys while lazy loading, but the current implementation does not allow this, maybe you can raise an issue.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文