Hibernate OneToOne между ПК с ленивым поведением - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь добиться, чтобы сущность с именем 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;

1 Ответ

0 голосов
/ 14 апреля 2020

После перехода по ссылке @SternK и обновления до Wildfly 19 и Hibernate 5.4.14 он наконец-то сработал, используя @MapsId.

Правильное сопоставление для использования:

MyEntity :

public class MyEntityImpl {

    @OneToOne(mappedBy = "myEntity", cascade = CascadeType.REMOVE, fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "SID")
    private MyEntityInfoImpl   info;

MyEntityInfo:

public class MyEntityInfoImpl {

    @OneToOne(fetch = FetchType.EAGER, optional = false)
    @MapsId
    @JoinColumn(name = "SID", referencedColumnName = "SID", insertable = false, updatable = false, nullable = false)
    private MyEntityImpl       myEntity;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...