JPA:选择实体的子集不会加载@OneToOne 属性

JPA: Selecting subset of entity won't load @OneToOne property

我有一个巨大的实体,我想加载它的子集(ID 和 baz 属性):

@Entity
public class GiganticEntity {

    @Id Long id;

    @OneToOne(mappedBy = "giganticEntity")
    Foo foo;

    @OneToOne(mappedBy = "giganticEntity")
    Bar bar;

    @OneToOne(mappedBy = "giganticEntity")
    Baz baz;

    // default constructor + getters/setters

    public GiganticEntity(Long id, Baz baz) {
        this.id = id;
        this.baz = baz;
    }
}

我尝试使用以下 JPA 查询,但 baz 属性 将为空:

"SELECT new package.GiganticEntity(ge.id, ge.baz) " +
"FROM GiganticEntity ge WHERE ge.id = 1";

我尝试添加显式连接,但结果也为空:

"SELECT new package.GiganticEntity(ge.id, b) FROM GiganticEntity ge " +
    "LEFT JOIN ge.baz as b " +
    "WHERE ge.id = 1";

如果我只是 select 我这样的巨大实体,那么一切正常(但我正在尝试保存一些连接):

"SELECT GiganticEntity g WHERE g.id = 1";

这可以用 JPA 实现吗?我正在使用 Hibernate 作为它的实现。

编辑:查询实际上需要LEFT JOIN,所以我需要所有巨大的实体baz -es.

为什么这么奇怪的构造?我宁愿

"SELECT GiganticEntity ge LEFT JOIN FETCH ge.baz WHERE g.id = 1 ";

"SELECT GiganticEntity ge FETCH ALL PROPERTIES WHERE g.id = 1 ";

由于 GiganticEntityBaz 具有反向一对一关联:

@OneToOne(mappedBy = "giganticEntity")
Baz baz;

意味着Baz也和GiganticEntity有关联:

@OneToOne
GiganticEntity giganticEntity;

查询因此可以变成:

select new package.GiganticEntity(g.id, b)  
from Baz b
join b.giganticEntity g
where g.id : id

编辑

根据题目要求修改:

Query actually needs to be LEFT JOIN, so I need all gigantic entites with baz-es.

您可以将多个实体映射到同一个 table。您将拥有包含所有关联和多个实体视图的 GiganticEntity

@Entity
@Table(name="GiganticEntity")
@Immutable
public class GignaticBazViewEntity {

    @Id Long id;

    @OneToOne(mappedBy = "bar")
    Bar bar;

    @OneToOne(mappedBy = "baz")
    Baz baz;

    public GiganticEntity(Long id, Bar bar, Baz baz) {
        this.id = id;
        this.bar = bar;
        this.baz = baz;
    }
}

查询是这样的:

select g
from GignaticBazViewEntity g
left join fetch g.bar
left join fetch g.baz
where g.id : id

select g
from GignaticBazViewEntity g
FETCH ALL PROPERTIES
where g.id : id

如果您不想总是获取 OneToOne(或 ManyToOne),您应该明确地将它们声明为惰性的(默认为 eager)。按如下方式更改您的代码:

@Entity
public class GiganticEntity {
    @Id Long id;

    @OneToOne(mappedBy = "giganticEntity", fetch = FetchType.LAZY)
    Foo foo;

    @OneToOne(mappedBy = "giganticEntity", fetch = FetchType.LAZY)
    Bar bar;

    @OneToOne(mappedBy = "giganticEntity", fetch = FetchType.LAZY)
    Baz baz;

    // default constructor + getters/setters
}

然后编写您的查询以获取您想要的内容:

SELECT GiganticEntity g LEFT JOIN FETCH g.baz WHERE g.id = 1

@OneToOne 关联必须定义为 optional = false。参见 this question and answer

是的,我知道这听起来很疯狂,但这是告诉 Hibernate 为关联实体创建代理的唯一方法。