Я пытаюсь добиться, чтобы сущность с именем MyEntity
вместе с другой сущностью с именем MyEntityInfo
использовала Hibernate 5.3.13. Наконец, с аннотациями под Wildfly 18.
Идея состоит в том, чтобы MyEntity
хранит некоторые часто запрашиваемые поля, а MyEntityInfo
хранит некоторые редко запрашиваемые поля. Оба имеют один и тот же первичный ключ, называемый SID (Long), и существует FK от SID Info до SID сущности. Там могут быть сущности без информации.
Обычно вам не потребуется дополнительная информация. Например, я не хочу, чтобы информационная сущность извлекалась, когда я запрашиваю свою сущность следующим образом:
MyEntityImpl entity = em.find(MyEntityImpl.class, 1L);
Однако, когда я запускаю этот код, я нахожу, что есть второй запрос, извлекающий информацию сущность вдоль основной, как в поведении EAGER
.
Я отображаю отношения, используя @OneToOne
. Я пробовал несколько комбинаций FetchType
, optional
и @LazyToOne
, но пока безуспешно.
Вот код для классов MyEntity и MyEntityInfo (дополнительные методы извлечения и установки удалены):
MyEntity (генератор идентификаторов - это генератор пользовательских последовательностей):
@Entity
@Table(name = MyEntityImpl.TABLE_NAME)
public class MyEntityImpl {
public static final String TABLE_NAME = "TMP_MY_ENTITY";
@Id
@GeneratedValue(strategy = GenerationType.TABLE, generator = "GEN_" +
TABLE_NAME)
@GenericGenerator(name = "GEN_" +
TABLE_NAME, strategy = CoreIdGenerator.ID_GENERATOR, parameters = {
@Parameter(name = "tableName", value = TABLE_NAME) })
@Column(name = "sid", nullable = false, unique = true)
private Long sid;
@OneToOne(mappedBy = "myEntity", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = true)
@LazyToOne(LazyToOneOption.NO_PROXY)
private MyEntityInfoImpl info;
@Column
private String field;
MyEntityInfo:
@Entity
@Table(name = MyEntityInfoImpl.TABLE_NAME)
public class MyEntityInfoImpl {
public static final String TABLE_NAME = "TMP_MY_ENTITY_INFO";
@Id
@Column(name = "SID", nullable = false, unique = true)
private Long sid;
@OneToOne(fetch = FetchType.EAGER, optional = false)
@JoinColumn(name = "SID", referencedColumnName = "SID", insertable = false, updatable = false, nullable = false)
private MyEntityImpl myEntity;
@Column(name = "INFO_FIELD")
private String infoField;
Я пробовал это решение, но, как я уже сказал, оно не не работают для меня:
Ленивая загрузка в спящем режиме для обходного решения один на один - как это работает?
Мне удалось сделать что-то похожее, используя @OneToMany
и управление данными вручную, но это не то, что я хотел бы сделать. Тем не менее, другие альтернативы и информация о том, можно ли этого достичь или нет с помощью @OneToOne
, или правильный шаблон проектирования для этого также приветствуются.
PS: Создание таблиц базы данных для SQL сервера, на случай, если Вы хотите попробовать это:
create table TMP_MY_ENTITY (SID NUMERIC(19,0) NOT NULL, FIELD VARCHAR(100));
go
ALTER TABLE TMP_MY_ENTITY ADD CONSTRAINT PK_TMP_MY_ENTITY PRIMARY KEY CLUSTERED (SID);
go
create table TMP_MY_ENTITY_INFO (SID NUMERIC(19,0) NOT NULL, INFO_FIELD VARCHAR(100));
go
ALTER TABLE TMP_MY_ENTITY_INFO ADD CONSTRAINT PK_TMP_MY_ENTITY_INFO PRIMARY KEY CLUSTERED (SID);
go
CREATE SEQUENCE SEQ_TMP_MY_ENTITY START WITH 1 INCREMENT BY 1 MINVALUE 1 CACHE 20;
alter table TMP_MY_ENTITY_INFO add constraint FK_TMP_MY_ENT_INFO_MY_ENT FOREIGN KEY (SID) references TMP_MY_ENTITY(SID);
go
insert into TMP_MY_ENTITY(SID, FIELD) VALUES (NEXT VALUE FOR SEQ_TMP_MY_ENTITY, 'Field 1');
insert into TMP_MY_ENTITY_INFO(SID, INFO_FIELD) VALUES ((SELECT MAX(SID) FROM TMP_MY_ENTITY), 'Info 1');
insert into TMP_MY_ENTITY(SID, FIELD) VALUES (NEXT VALUE FOR SEQ_TMP_MY_ENTITY, 'Field 2');
insert into TMP_MY_ENTITY_INFO(SID, INFO_FIELD) VALUES ((SELECT MAX(SID) FROM TMP_MY_ENTITY), 'Info 2');
insert into TMP_MY_ENTITY(SID, FIELD) VALUES (NEXT VALUE FOR SEQ_TMP_MY_ENTITY, 'Field 3 no info');
-- DELETE ALL
drop table TMP_MY_ENTITY_INFO;
drop table TMP_MY_ENTITY;
drop sequence SEQ_TMP_MY_ENTITY;