【问题标题】:JPA: Selecting subset of entity won't load @OneToOne propertyJPA:选择实体的子集不会加载@OneToOne 属性
【发布时间】:2015-06-24 20:00:03
【问题描述】:

我有一个巨大的实体,我想加载它的子集(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";

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

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

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

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

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

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

【问题讨论】:

  • 你试过LEFT JOIN FETCH 还是FETCH ALL PROPERTIES ??
  • 你考虑过让foobar变得懒惰吗?
  • 您对建议的解决方案有更多期望吗?恐怕如果你不能让OneToOne 变得懒惰,你将不得不删除它们。否则,即使在查询中显式实例化,baz 仍将加载 GiganticEntity...
  • 不,我想我会选择弗拉德的答案。

标签: java hibernate jpa orm hibernate-mapping


【解决方案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

编辑

根据题型要求变化:

查询实际上需要 LEFT JOIN,所以我需要所有巨大的实体 与 baz-es。

您可以将多个实体映射到同一个表。您将拥有包含所有关联和多个实体视图的 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

【讨论】:

  • 谢谢,这行得通,但请查看我的编辑 - 我实际上需要所有巨大的实体加入 baz ......无论如何用你的方法做到这一点?
  • 使用这种方法,我们最终会加载 GignaticEntity 的所有急切依赖项 - 因为 @OneToOne(mappedBy = "baz") 意味着原始的 Baz 类仍然引用 GiganticEntity 而不是 @ 987654335@。所以除非有其他解决方法,否则我还需要两次映射“Baz”类?
  • 检查我更新的查询。您可以使用 fetch 指令。
  • 谢谢,但不是我想要的。我想说mappedBy = "baz" 意味着映射的另一端在GiganticEntity 内部,而notGiganticBazViewEntity 内部。因此它会从原始映射中选择一些东西(我试图避免的连接)。
  • MappedBy 说 Bar 也有一个 GiganticEntity 关联。您可以对同一个表进行多个映射,并且在没有连接的情况下,它必须执行辅助选择,如果您删除了 fetch 指令,这在我的示例中也有效。你应该先试一试。
【解决方案2】:

为什么会有这样的结构?我宁愿

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

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

【讨论】:

  • 这正是我不想避免的 :) "foo" 和 "bar" 也将被急切地获取,我正在努力防止这种情况发生!
  • LEFT JOIN FETCH 更渴望只获取 baz。
  • 不幸的是,如果我尝试这样做:stackoverflow.com/questions/11164496/…
【解决方案3】:

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

@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

【讨论】:

  • 感谢您的建议,我修复了问题中的映射。这将是一种显而易见的方法,但它不起作用,因为 foo/bar/baz 是可选关系(我应该在问题中指定)。在这里查看更多 -> stackoverflow.com/a/1445694/314073
  • 啊,我记得那个。但是也有一些解决方案,比如字节码检测或丑陋的@OneToMany 解决方法。
【解决方案4】:

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

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

【讨论】:

  • 这里的问题是,它实际上一个可选的关联。
  • 对不起,你好像没听懂。要使其延迟加载,您必须说它是 NOT 可选的,即使它是可选的。我知道这听起来很重要,但是您需要仔细阅读其他问题并回答才能理解它。您实际上是在“愚弄” Hibernate 认为它不需要加载关联,因为您告诉它它必须存在,因此同时为其创建一个代理。试试看。
  • 因此,如果您想始终加载 Baz,则需要将该关联设为 optional = true,并将 Foo 和 Bar 设为 optional = false
猜你喜欢
  • 1970-01-01
  • 2019-04-28
  • 1970-01-01
  • 1970-01-01
  • 2011-09-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多