web-dev-qa-db-fra.com

Mise en veille prolongée: chargement différé univoque, facultatif = faux

J'ai rencontré le problème que le chargement différé un-à-un ne fonctionne pas en hibernation. Je l'ai déjà résolu , mais toujours pas correctement comprendre ce qui se passe.

Mon code ( le chargement paresseux ne fonctionne pas ici , lorsque je tire Personne - L'adresse est également récupérée):

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

Mais : si j'ajoute optional=false dans la relation OneToOne, le chargement paresseux fonctionne bien !

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

Question/Intervention: s'il vous plaît, expliquez-moi comment optional=false l'annotation permet de réaliser un chargement paresseux.

PS J'ai lu des articles post1 et post2 , et je comprends pourquoi OneToOne simple ne peut pas être paresseux, mais je ne sais toujours pas optional=false la magie.

52
VB_

Si l'association est facultative, Hibernate n'a aucun moyen de savoir s'il existe une adresse pour une personne donnée sans émettre de requête. Il ne peut donc pas remplir le champ d'adresse avec un proxy, car il ne peut y avoir aucune adresse référençant la personne, et il ne peut pas le remplir avec null, car il peut y avoir une adresse référençant la personne.

Lorsque vous rendez l'association obligatoire (c'est-à-dire optional=false), il vous fait confiance et suppose qu'une adresse existe, puisque l'association est obligatoire. Il remplit donc directement le champ d'adresse avec un proxy, sachant qu'il existe une adresse référençant la personne.

77
JB Nizet

Le plus simple est de simuler une relation un-à-plusieurs. Cela fonctionnera car le chargement paresseux de la collection est beaucoup plus facile que le chargement paresseux d'une seule propriété nullable mais généralement cette solution est très gênante si vous utilisez des requêtes JPQL/HQL complexes.

L'autre consiste à utiliser l'instrumentation de bytecode de construction. Pour plus de détails, veuillez lire la documentation Hibernate: 19.1.7. Utilisation de la récupération de propriété paresseuse. N'oubliez pas que dans ce cas, vous devez ajouter une annotation @LazyToOne(LazyToOneOption.NO_PROXY) à une relation un-à-un pour la rendre paresseuse. La définition de fetch sur LAZY n'est pas suffisante.

La dernière solution consiste à utiliser l'instrumentation de bytecode d'exécution, mais cela ne fonctionnera que pour ceux qui utilisent Hibernate comme fournisseur JPA dans un environnement JEE complet (dans ce cas, définir "hibernate.ejb.use_class_enhancer" Sur true devrait faire l'affaire: Entity Manager Configuration) ou utilisez Hibernate avec Spring configuré pour effectuer le tissage d'exécution (cela peut être difficile à réaliser sur certains serveurs d'applications plus anciens). Dans ce cas, une annotation @LazyToOne(LazyToOneOption.NO_PROXY) est également requise.

8
sendon1982