休眠:一对一延迟加载,可选= false


70

我遇到了一个问题,即一对一的延迟加载在休眠状态下不起作用。我已经解决了它,但是仍然无法正确理解会发生什么。

我的代码(延迟加载在这里不起作用,当我拉人时-地址也被获取):

@Entity
public class Person{

  @Id
  @SequenceGenerator(name = "person_sequence", sequenceName = "sq_person")
  @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "person_sequence")
  @Column(name = "id")
  private long personID;

  @OneToOne(mappedBy="person", cascade=CascadeType.ALL, fetch = FetchType.LAZY)
  private Adress address;
  //.. getters, setters
}

@Entity
public class Address {

  @Id
  @Column(name="id", unique=true, nullable=false)
  @GeneratedValue(generator="gen")
  @GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="person"))
  private long personID;

  @PrimaryKeyJoinColumn
  @OneToOne
  private FileInfo person;
}

但是:如果添加optional=falseOneToOne关系,则延迟加载可以正常工作

@OneToOne(mappedBy="person", cascade=CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
private Adress address;

问题/完整性:请向我解释optional=false注释如何帮助实现延迟加载。

PS我已经阅读了post1post2的帖子,并了解了为什么简单的OneToOne不能偷懒,但是我仍然无法掌握optional=false魔术。


嘿@Volodymyr,我也遇到同样的问题。我正在尝试从实体中分离BLOB列。父实体有子实体。子实体包含二进制列。父母和孩子都是same table这样,所以我使用@OneToOne关系。尽管我使用了LAZY fetchType,但似乎无法正常工作。当我放时optional=false,它起作用。任何解释将不胜感激。
emeraldhieu 2015年

@ Emerald214对不起,那是2年前。目前,我正在写JS Mobile,无法帮助您
-VB_

OneToOne可选= false不适用于CascadeType.PERSIST,请参见:hibernate.atlassian.net/browse/HHH-9670
Sliver

Answers:


95

如果关联是可选的,则Hibernate无法在不发出查询的情况下知道给定人员的地址是否存在。因此,它不能使用代理填充地址字段,因为可能没有引用该人的地址,并且它不能填充null,因为可能存在一个引用该人的地址。

当您使关联成为强制性(即optional=false)时,由于关联是强制性的,因此它信任您并假定存在一个地址。因此,在知道存在引用该人的地址的情况下,它直接用代理填充地址字段。


1
如果您尝试保存Personne没有住址可选=假不工作:“org.hibernate.PropertyValueException:非空属性引用null或瞬时值:”
了Grégory

6
optional = false表示...地址不是可选的。因此这是强制性的。因此,将其设置为null会引发异常。这是完全可以预期的。
JB Nizet

3
除了它实际上不会延迟加载关联之外,还有可能。也可以通过使用LazyToOne(NO_PROXY)并在构建时检测字节码IIRC来实现,但是我对此有不好的经验。如果关联是可选的,则最好使用专用的连接列。
JB Nizet

1
是的,我已经在构建时测试过LazyToOne(NO_PROXY)并检测了字节码,但是像您一样有糟糕的经验(使用另一个lib HibernateJackson)。我最终决定不映射关联,并在不同的DAO中分别管理表。
了Grégory

1
optional = false,对我不起作用,它仍会急切地获取那些实体。@OneToOne(fetch = FetchType.LAZY,mappingBy =“ fundSeries”,可选= false)私人FundSeriesDetailEntity fundSeriesDetail;
Oleg Kuts

11

最简单的方法是伪造一对多关系。这将起作用,因为延迟加载集合比延迟加载单个可为空的属性要容易得多,但是通常,如果使用复杂的JPQL / HQL查询,此解决方案将非常不便。

另一种是使用构建时字节码检测。有关更多详细信息,请阅读Hibernate文档:19.1.7。使用懒惰的属性获取。请记住,在这种情况下,必须将@LazyToOne(LazyToOneOption.NO_PROXY)注释添加到一对一关系以使其变得懒惰。仅将获取设置为LAZY是不够的。

最后一种解决方案是使用运行时字节码检测,但是它仅适用于在成熟的JEE环境中将Hibernate用作JPA提供程序的用户(在这种情况下,将“ hibernate.ejb.use_class_enhancer”设置为true应该可以解决问题:Entity Manager Configuration)或将Hibernate与Spring配置为进行运行时编织(在某些较旧的应用程序服务器上可能很难实现)。在这种情况下@LazyToOne(LazyToOneOption.NO_PROXY),也需要注释。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.