Hibernate генерирует SQL-запросы при доступе к идентификатору связанной сущности - PullRequest
8 голосов
/ 17 сентября 2010

У меня есть Hibernate Entities, которые выглядят примерно так (геттеры и сеттеры пропущены):

@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 (как и Lazy). Если я хочу получить доступ к идентификатору родителя, я выполняю следующий вызов:

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

Как я понимаю, вызов НЕ должен совершать обход в базу данных, поскольку идентификатор хранится в таблице EntityA, и прокси-сервер должен возвращать только это значение. Однако в моем случае это создает оператор SQL, который выбирает EntityB и только затем возвращает Id.

Как я могу исследовать проблему? Каковы некоторые вероятные причины этого неправильного поведения?

Ответы [ 2 ]

10 голосов
/ 18 сентября 2010

Как я понимаю, вызов НЕ должен совершать обход в базу данных, так как идентификатор хранится в таблице EntityA, и прокси должен только возвращать это значение.

Использовать тип доступа к свойству . Поведение, которое вы испытываете, является «ограничением» типа доступа к полю. Вот как Эммануэль Бернард объяснил это:

Это прискорбно, но ожидаемо. Это одно из ограничений доступа на уровне поля. По сути, мы не можем знать, что 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 голосов
/ 18 сентября 2010

То, что вы говорите, имеет смысл - что это не приведет к попаданию в БД, поскольку EntityA содержит родительский идентификатор.Я просто не уверен, действительно ли вызов getParent () загружает объект EntityB независимо от того, интересует ли вас только ID.Вы можете попробовать пометить дочернюю коллекцию (и любые другие поля) как Lazy, если хотите сохранить попадание в базу данных.

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