本文介绍了在具有懒惰行为的PK之间休眠OneToOne的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用Hibernate 5.3.13.Wildfly 18下的注解最终拥有一个名为MyEntity的实体以及另一个名为MyEntityInfo的实体.

I'm trying to achieve to have an entity called MyEntity along with another entity called MyEntityInfo using Hibernate 5.3.13.Final with annotations under Wildfly 18.

这个想法是让MyEntity存储一些通常要求的字段,而MyEntityInfo存储一些很少要求的字段.两者共享一个相同的主键,称为SID(Long),并且从Info的SID到Entity的SID都有一个FK.可能有没有信息的实体.

The idea is to have MyEntity store some commonly requested fields, and MyEntityInfo store some rarely requested fields. Both share the same primary key called SID (Long), and there is a FK from Info's SID to Entity's SID. There can be entities without info.

通常,您不需要其他信息.例如,当我查询这样的实体时,我不希望获取信息实体:

Normally you will not require the additional info. For example, I don't want the info entity to be fetched when I query my entity like this:

MyEntityImpl entity = em.find(MyEntityImpl.class, 1L);

但是,当我运行这段代码时,我发现还有第二个查询,沿着主要查询获取Info实体,就像在EAGER行为中一样.

However, when I run this code, I find that there's a second query, fetching the Info entity along the main one, as in an EAGER behaviour.

我正在使用@OneToOne映射关系.我已经尝试了FetchTypeoptional@LazyToOne的几种组合,但是到目前为止没有成功.

I'm mapping the relationship using @OneToOne. I've tried several combinations of FetchType, optional and @LazyToOne, but so far without success.

这是MyEntity和MyEntityInfo类的代码(已删除其他getter和setter):

Here is the code for both MyEntity and MyEntityInfo classes (additional getters and setters removed):

MyEntity(ID生成器是自定义序列生成器):

MyEntity (ID generator is a custom sequence generator):

@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:

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;

我已经尝试过此解决方案,但正如我所说,它对我不起作用:

I've tried this solution, but as I said, it didn't work for me:

休眠延迟加载一对一的解决方法-如何运作?

我已经设法使用@OneToMany和手动管理数据来做一些类似的事情,但这不是我想要做的.但是,也欢迎使用@OneToOne是否可以实现此目标的另一种替代方法和信息,或执行此操作的正确设计模式.

I've managed to do something somewhat similar using @OneToMany and managing data manually, but that's not what I'd like to do. However, another alternatives and information on whether this can be achieved or not using @OneToOne, or the right design pattern to do this are also welcome.

PS:为SQL Server创建数据库表,以备您尝试:

PS: Database tables creation for SQL Server, in case you want to try it:

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;

推荐答案

在跟随@SternK链接并升级到Wildfly 19和Hibernate 5.4.14之后,它终于可以使用@MapsId了.

After following @SternK link, and upgrading to Wildfly 19 and Hibernate 5.4.14, it finally worked by using @MapsId.

要使用的正确映射是这样:

The right mapping to use is this:

MyEntity:

public class MyEntityImpl {

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

MyEntityInfo:

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;

这篇关于在具有懒惰行为的PK之间休眠OneToOne的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

07-02 18:05