Hibernate在访问关联实体的ID时生成SQL查询

问题描述 投票:8回答:3

我有一个看起来像这样的休眠实体(省略了getter和setter的方法:]

@Entity
public class EntityA {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    private EntityB parent;
}

@Entity
public class EntityB extends SuperEntity {
    @OneToMany(mappedBy = "parent")
    @Fetch(FetchMode.SUBSELECT)
    @JoinColumn(name = "parent_id")
    private Set<EntityA> children;
}

@MappedSuperclass
public class SuperEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private long itemId;
}

当我查询EntityA时,它加载得很好,其父关联被一个Hibernate代理(因为它是惰性的)代替了。如果我想访问父母的身份证,请执行以下调用:

EntityA entityA = queryForEntityA();
long parentId = entityA.getParent().getItemId();

据我所知,调用不应往返于数据库,因为Id存储在EntityA表中,并且代理应仅返回该值。但是,在我的情况下,这会生成一条SQL语句,该语句将提取EntityB并仅返回ID。

我该如何调查问题?这种不正确行为的一些可能原因是什么?

java hibernate orm proxy lazy-loading
3个回答
10
投票

据我所知,调用不应往返于数据库,因为Id存储在EntityA表中,并且代理应仅返回该值。

使用属性访问类型。您遇到的行为是字段访问类型的“限制”。这是伊曼纽尔·伯纳德(Emmanuel Bernard)的解释:

这是不幸的,但是是预期的。这是字段级别访问的限制之一。基本上,我们没有办法知道getId()实际上只能访问id字段。因此,为了安全起见,我们需要加载整个对象。

因此将您的代码更改为:

@Entity
public class EntityA {
    private EntityB parent;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "parent_id")
    public EntityB getParent() {
        return parent; 
    }
    ...
}

@MappedSuperclass
public class SuperEntity {
    private long itemId;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    public long getItemId() { 
        return itemId;
    }
    ...
}

相关问题

参考


0
投票

您说的是有道理的-因为EntityA包含父ID,所以不会命中数据库。我只是不确定getParent()调用是否实际上加载EntityB对象,而不管您是否对ID感兴趣。如果要保存数据库匹配,可以尝试将子级集合(和其他任何字段)标记为“惰性”。

@Entity
public class EntityB : SuperEntity {
    @OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
    @Fetch(FetchMode.SUBSELECT)
    @JoinColumn(name = "parent_id")
    private Set<EntityA> children;
}

0
投票

关于休眠:This behavior自Hibernate 5.2.12起已更改。


0
投票

关于休眠:This behavior自Hibernate 5.2.12起已更改。

© www.soinside.com 2019 - 2024. All rights reserved.