Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

I have Hibernate Entities that look something like this (getters and setters left out):

@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;
}

When I query for EntityA it loads fine, with the parent association being replaced by a Hibernate proxy (as it is Lazy). If I want access to the parent's id I perform the following call:

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

As I understand that call should NOT make a roundtrip to the database, as the Id is stored in the EntityA table, and the proxy should only return that value. However, in my case this generates a SQL statement which fetches EntityB and only then returns the Id.

How can I investigate the problem? What are some likely causes of this incorrect behaviour?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
214 views
Welcome To Ask or Share your Answers For Others

1 Answer

As I understand that call should NOT make a roundtrip to the database, as the Id is stored in the EntityA table, and the proxy should only return that value.

Use property access type. The behavior you're experiencing is a "limitation" of field access type. Here is how Emmanuel Bernard explained it:

That is unfortunate but expected. That's one of the limitations of field level access. Basically we have no way to know that getId() indeed only go and access the id field. So we need to load the entire object to be safe.

So change your code into:

@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;
    }
    ...
}

Related question

References


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share

548k questions

547k answers

4 comments

86.3k users

...