一尘不染

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

hibernate

我有一些看起来像这样的Hibernate实体(省略了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代理(因为它是惰性的)代替了。如果要访问父母的ID,请执行以下调用:

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

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

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


阅读 242

收藏
2020-06-20

共1个答案

一尘不染

据我了解,该调用不应往返于数据库,因为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;
    }
    ...
}

参考文献

2020-06-20