我正在尝试使用Hibernate 5.3.13.Final在Wildfly 18下使用注解来实现一个名为MyEntity
的实体以及另一个名为MyEntityInfo
的实体。
这个想法是让MyEntity
存储一些通常要求的字段,而MyEntityInfo
存储一些很少要求的字段。两者共享一个称为SID(长)的相同主键,并且从Info的SID到实体的SID都有一个FK。可能有没有信息的实体。
通常,您不需要其他信息。例如,当我查询这样的实体时,我不希望获取信息实体:
MyEntityImpl entity = em.find(MyEntityImpl.class, 1L);
但是,当我运行此代码时,我发现还有第二个查询,沿着主要查询获取Info实体,如
EAGER
行为所示。我正在使用
@OneToOne
映射关系。我已经尝试了FetchType
,optional
和@LazyToOne
的几种组合,但是到目前为止没有成功。这是MyEntity和MyEntityInfo类的代码(已删除其他getter和setter):
MyEntity(ID生成器是自定义序列生成器):
@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;
我已经尝试过此解决方案,但正如我所说,它对我不起作用:
Hibernate lazy loading for reverse one to one workaround - how does this work?
我已经设法使用
@OneToMany
进行了一些类似的操作并手动管理数据,但这不是我想要的。但是,也欢迎使用@OneToOne
或是否可以使用实现此目的的另一种选择和信息。PS:为SQL Server创建数据库表,以备您尝试:
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
了。
正确使用的映射是这样的:
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;