Hibernate OneToOne автоматическое извлечение соединения (решение проблемы n + 1) - PullRequest
8 голосов
/ 11 августа 2011

у нас есть проблема выбора n + 1 с Hibernate 3.3.

Для простоты я просто сделаю небольшой абстрактный пример.

Предположим, у нас есть следующие простые классы:

class MainEntity {
  @Id
  public Long id; //we have a table generator create this id

  @OneToOne ( mappedBy ="main" )
  public SubEntity subEntity;
}

class SubEntity {
 @Id
 @Column( name = "mainId" ) //note that this is the same column as the join column below
 public Long mainId; //in order to have the exact same id as the corresponding MainEntity

 @OneToOne ( fetch = FetchType.LAZY )
 @JoinColumn ( name = "mainId", insertable = false, updatable = false, nullable = false )
 public MainEntity main; //this is used for navigation and queries (" ... subentity.main = :x")
}

Итак, как видите, SubEntity имеет отношение к MainEntity, которое выражается двумя свойствами, где свойство mainId является тем, которое отвечает за управление отношением / внешним ключом.

Это работает довольно хорошо и идеально соответствует нашим потребностям.

Однако есть одна проблема с энергичной загрузкой SubEntity вместе с MainEntity.

Предположим, у меня есть запроскоторый возвращает коллекцию MainEntity.При текущей настройке Hibernate выдаст n + 1 выбор: сам запрос + n выбор для каждого SubEntity.

Конечно, я мог бы добавить join fetch к запросу, но я бы предпочелHibernate, чтобы сделать это автоматически.Таким образом я попытался добавить @Fetch( FetchMode.JOIN ), но это ничего не дало.

У меня также не возникло бы проблем с использованием @Fetch( FetchMode.SUBSELECT ), что должно уменьшить операторы выбора до 2 - исходный запрос и выбор длядочерние объекты (по крайней мере, так происходит с другим свойством, помеченным @CollectionOfElements и @Fetch( FetchMode.SUBSELECT )).


Таким образом, вопрос заключается в следующем: как бы я сказал Hibernate автоматически присоединиться к выборке или использовать один выбор для быстрой загрузки дочерних объектов?Я что-то пропустил?

Заранее спасибо,

Томас

PS: Единственной проблемой, которая может быть проблемой, может быть mappedBy = "main", который не ссылается на фактический столбец идентификатора, но яне может изменить его на mappedBy = "id".

Ответы [ 2 ]

8 голосов
/ 11 августа 2011

Если вы хотите разделить первичные ключи между MainEntity и SubEntity, используйте аннотации PrimaryKeyJoinColumn и MapsId.

При использовании PrimaryKeyJoinColumn объект загружается путем объединения таблицы MainEntity с таблицей SubEntity с использованием того же первичного ключа. Это должно решить проблемы n + 1.

Аннотация MapsId просит Hibernate скопировать идентификатор из другая связанная сущность в нашем примере скопирует SubEntity.mainEntity.id в SubEntity.id.

@Entity
public class MainEntity {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "main_Id")
    private Long id;

    @OneToOne(cascade = CascadeType.ALL)
    @PrimaryKeyJoinColumn
    private SubEntity  subEntity ;
}


@Entity
public class SubEntity 
{
    @Id @Column(name="main_Id_FK") Long id;

    @MapsId 
    @OneToOne
    @JoinColumn(name = "main_Id_FK")    
    @PrimaryKeyJoinColumn
    private MainEntity mainEntity;        

}

Справочная документация Hibernate:

PrimaryKeyJoinColumn
MapsId

1 голос
/ 11 августа 2011

Есть три варианта, чтобы избежать вопросов n +1:

 Lot size

 subselect

 Make a LEFT JOIN in the query

Здесь FAQ1 Здесь FAQ2

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...