Ruhezustand: Eins-zu-eins-verzögertes Laden, optional = falsch

70

Ich hatte das Problem, dass eins zu eins verzögertes Laden im Ruhezustand nicht funktioniert. Ich habe es bereits gelöst , verstehe aber immer noch nicht richtig , was passiert.

Mein Code ( verzögertes Laden funktioniert hier nicht , wenn ich Person - Adresse abrufe, wird auch abgerufen):

@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;
}

Aber : Wenn ich hinzufügen , optional=falsein OneToOne Beziehung, verzögertes Laden funktioniert gut !

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

Frage / Bitte: Erklären Sie mir bitte, wie optional=falseAnmerkungen dazu beitragen , ein verzögertes Laden zu erreichen.

PS Ich habe die Beiträge post1 und post2 gelesen und verstehe, warum OneToOne nicht faul sein kann, aber ich kann optional=falseMagie immer noch nicht verstehen .

VB_
quelle
Hey @Volodymyr, ich habe das gleiche Problem mit dir. Ich versuche, eine BLOB-Spalte von einer Entität zu trennen. Übergeordnete Entität hat untergeordnete Entität. Die untergeordnete Entität enthält eine binäre Spalte. Eltern und Kind sind die, same tablealso benutze ich die @ OneToOne-Beziehung. Ich habe zwar LAZY fetchType verwendet, aber es scheint nicht zu funktionieren. Wenn ich sage optional=false, funktioniert es. Jede Erklärung wird sehr geschätzt.
Smaragdhieu
@ Emerald214 sorry, das war vor 2 Jahren. Derzeit schreibe ich JS Mobile und kann Ihnen nicht helfen
VB_
OneToOne optional = false funktioniert nicht mit CascadeType.PERSIST siehe: hibernate.atlassian.net/browse/HHH-9670
Splitter

Antworten:

95

Wenn die Zuordnung optional ist, kann der Ruhezustand nicht feststellen, ob für eine bestimmte Person eine Adresse vorhanden ist, ohne eine Abfrage zu erstellen. Daher kann das Adressfeld nicht mit einem Proxy gefüllt werden, da möglicherweise keine Adresse vorhanden ist, die auf die Person verweist, und es kann nicht mit nulldieser Adresse gefüllt werden, da möglicherweise eine Adresse vorhanden ist, die auf die Person verweist.

Wenn Sie die Zuordnung obligatorisch machen (dh optional=false), vertraut sie Ihnen und geht davon aus, dass eine Adresse vorhanden ist, da die Zuordnung obligatorisch ist. Daher wird das Adressfeld direkt mit einem Proxy gefüllt, da bekannt ist, dass eine Adresse auf die Person verweist.

JB Nizet
quelle
1
optional = false funktioniert nicht, wenn Sie versuchen, die Personne ohne Adresse zu speichern: "org.hibernate.PropertyValueException: Die Eigenschaft not-null verweist auf einen Null- oder Übergangswert:"
Grégory
6
optional = false bedeutet, dass ... die Adresse nicht optional ist. Es ist also obligatorisch. Wenn Sie also Null setzen, wird eine Ausnahme ausgelöst. Das ist durchaus zu erwarten.
JB Nizet
3
Es ist möglich, außer dass die Zuordnung nicht faul geladen wird. Es ist auch möglich, LazyToOne (NO_PROXY) zu verwenden und den Bytecode zur Erstellungszeit IIRC zu instrumentieren, aber ich habe schlechte Erfahrungen damit gemacht. Verwenden Sie besser eine dedizierte Join-Spalte, wenn die Zuordnung optional ist.
JB Nizet
1
Ja, ich habe LazyToOne (NO_PROXY) getestet und den Bytecode beim Erstellen instrumentiert, habe aber schlechte Erfahrungen wie Sie gemacht (mit einer anderen lib HibernateJackson). Ich habe mich schließlich entschieden, die Zuordnung nicht zuzuordnen und die Tabelle in verschiedenen DAO separat zu verwalten.
Grégory
1
optional = false, funktioniert bei mir nicht, es holt diese Entität immer noch eifrig ab. @OneToOne (fetch = FetchType.LAZY, mappedBy = "fundSeries", optional = false) private FundSeriesDetailEntity fundSeriesDetail;
Oleg Kuts
11

Am einfachsten ist es, eine Eins-zu-Viele-Beziehung vorzutäuschen. Dies funktioniert, da das verzögerte Laden der Sammlung viel einfacher ist als das verzögerte Laden einer einzelnen nullbaren Eigenschaft. Im Allgemeinen ist diese Lösung jedoch sehr unpraktisch, wenn Sie komplexe JPQL / HQL-Abfragen verwenden.

Die andere Möglichkeit besteht darin, die Bytecode-Instrumentierung für die Erstellungszeit zu verwenden. Weitere Informationen finden Sie in der Dokumentation zum Ruhezustand: 19.1.7. Verwenden des verzögerten Abrufs von Eigenschaften. Denken Sie daran, dass Sie in diesem Fall @LazyToOne(LazyToOneOption.NO_PROXY)der Eins-zu-Eins-Beziehung Anmerkungen hinzufügen müssen , um sie faul zu machen. Es reicht nicht aus, Fetch auf LAZY zu setzen.

Die letzte Lösung besteht darin, die Laufzeit-Bytecode-Instrumentierung zu verwenden. Sie funktioniert jedoch nur für Benutzer, die Hibernate als JPA-Anbieter in einer vollständigen JEE-Umgebung verwenden (in diesem Fall sollte die Einstellung " hibernate.ejb.use_class_enhancer" auf "true" den Trick ausführen: Entity Manager-Konfiguration) oder "Hibernate with" verwenden Spring ist für das Weben zur Laufzeit konfiguriert (dies ist auf einigen älteren Anwendungsservern möglicherweise schwer zu erreichen). In diesem Fall @LazyToOne(LazyToOneOption.NO_PROXY)ist auch eine Anmerkung erforderlich.

sendon1982
quelle