У меня есть следующая сущность (показаны только соответствующие сопоставления):
@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Integer id;
@Column
private String name;
@ManyToOne(fetch = FetchType.LAZY) // lazy XToOne
@JoinColumn(name = "user_id", referencedColumnName = "person_id")
private User user;
@OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
private Group group;
@OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
private Tendering tendering;
...
}
Обратите внимание на комментарии выше: существует три @XToOne
отношения с другими сущностями:
Пользователь (подкласс SecurityIdentity с простым идентификатором в виде PK, на который ссылается PQ, представляющий владельца):
@Entity
@Table(name = "Users")
@DiscriminatorValue(value = "user")
public class User extends SecurityIdentity
{
@Column
private String name;
@OneToMany(mappedBy = "user")
private Set<PQ> pqs = new HashSet<PQ>();
...
}
Группа (также подкласс SecurityIdentity с простым идентификатором в видеPK, ссылается на PQ для представления набора пользователей, которые могут взаимодействовать с этим PQ):
@Entity
@Table(name = "Groups")
@DiscriminatorValue(value = "group")
public class Group extends SecurityIdentity
{
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pq_id", referencedColumnName = "id")
private PQ pq;
...
}
Тендер :
@Entity
@Table(name = "Tenderings")
public class Tendering implements Serializable
{
@Id
@Column(name = "pq_id", insertable = false, updatable = false)
private Integer pqId;
@Column(name = "external_code")
private String externalCode;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "pq_id", referencedColumnName = "id")
private PQ pq;
...
}
Не путайтео группах и пользователях, разделяющих идентификаторы, просто рассматривайте их как простые идентификаторы.Тендер - это просто отдельный объект документа (один-к-одному).
Как вы можете видеть, существует три отношения @XToOne
для объекта PQ, которые, если тип выборки не был установлен, будут загруженыс нетерпением (JPA по умолчанию).Поэтому, чтобы предотвратить это, я пометил все @XToOne
отношения как FetchType.LAZY
.
Теперь при использовании
em.find(PQ.class, someExistingId);
я получаю вывод Hibernate:
23:53:55,815 INFO [stdout] Hibernate: select pq0_.id as id291_0_, pq0_.description as descript2_291_0_, pq0_.name as name291_0_, pq0_.submission_date as submission4_291_0_, pq0_.user_id as user5_291_0_ from PQs pq0_ where pq0_.id=?
23:53:55,818 INFO [stdout] Hibernate: select user0_.id as id280_0_, user0_1_.identity_type_id as identity2_280_0_, user0_.is_enabled as is1_297_0_, user0_.name as name297_0_, user0_.password as password297_0_, user0_.person_id as person5_297_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
23:53:55,821 INFO [stdout] Hibernate: select group0_.id as id280_0_, group0_1_.identity_type_id as identity2_280_0_, group0_.pq_id as pq2_281_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?
23:53:55,823 INFO [stdout] Hibernate: select tendering0_.pq_id as pq1_296_0_, tendering0_.binary_file as binary2_296_0_, tendering0_.customer_id as customer6_296_0_, tendering0_.description as descript3_296_0_, tendering0_.external_code as external4_296_0_, tendering0_.title as title296_0_ from Tenderings tendering0_ where tendering0_.pq_id=?
Три дополнительных SELECT происходят из отношений @XToOne (как описано во многих местах в сети).Источник, на который я в основном смотрю, таков:
Создание ленивого отношения OneToOne
Как уже упоминалось, отношение @ManyToOne
User user
не должно бытьизвлечено:
@ManyToOne(fetch=FetchType.LAZY)
должно работать очень хорошо.
... здесь отношения от PQ до Пользователь , но он извлекается, как вы можете видеть из оператора select user0_.id as id280_0_, ...
...
Для остальных двух Group group
и Tendering tendering
, оба @OneToOne
реверс отображений, внешние ключи ссылаются на PK (ID) таблицы PQ, что приводит к одинаковому отображению в объекте PQ.
Обратите внимание, что все три отношения не являются обязательными: у PQ всегда есть владелец (пользователь), и PQ всегда ссылается на тендер и групповой объект.Я просто еще не смоделировал это в JPA выше ...
Итак, при добавлении optional = false
к трем отношениям сущности PQ:
@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Integer id;
@Column
private String name;
@ManyToOne(fetch = FetchType.LAZY, optional = false)
@JoinColumn(name = "user_id", referencedColumnName = "person_id")
private User user;
@OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
private Group group;
@OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
private Tendering tendering;
...
}
... я получаюследующий вывод Hibernate:
00:47:34,397 INFO [stdout] Hibernate: select pq0_.id as id361_0_, pq0_.description as descript2_361_0_, pq0_.name as name361_0_, pq0_.submission_date as submission4_361_0_, pq0_.user_id as user5_361_0_ from PQs pq0_ where pq0_.id=?
00:47:34,410 INFO [stdout] Hibernate: select user0_.id as id350_0_, user0_1_.identity_type_id as identity2_350_0_, user0_.is_enabled as is1_367_0_, user0_.name as name367_0_, user0_.password as password367_0_, user0_.person_id as person5_367_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
00:47:34,413 INFO [stdout] Hibernate: select group0_.id as id350_0_, group0_1_.identity_type_id as identity2_350_0_, group0_.pq_id as pq2_351_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?
Обратите внимание, что я играл только с optional = false
на объекте PQ, так как именно этот я использую в em.find(...)
.(Если этого недостаточно, пожалуйста, просветите меня.)
Мой вопрос теперь имеет два аспекта:
- Почему с энтузиазмом извлекается сущность
@ManyToOne
для User
(учитывая, что это, как говорят, работает лениво, см. Создание отношения OneToOne ленивым )? - Почему только отношение
OneToOne
к сущности Tendering
прекращается, извлекается?Это потому, что объект Tendering
ссылается на столбец PK PQ как на сам PK (@Id
in Tendering
), а объект Group
(обычное отношение к PK PQ) отсутствует?
Что не так?Как мне сделать эти необязательные отношения ленивыми?(без инструментария кода или других взломов, просто аннотации ...)
Я знаю, что LAZY - это всего лишь подсказка для JPA-провайдера, что-то делать с отложенной загрузкой или нет, но в этом случае кажется, чтокак будто что-то не так (как часть этого работает).
PS: я использую Hibernate 4.0 BETA, версию, которая поставляется с JBoss 7.0.0.Final вместе только с аннотациями JPA (вышесовместимы с JPA 1.0).