问题描述
我正在尝试使用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
映射关系.我已经尝试了FetchType
,optional
和@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的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!