我有一些看起来像这样的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。
我该如何调查问题?这种错误行为的一些可能原因是什么?
据我了解,该调用不应往返于数据库,因为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; } ... }