web-dev-qa-db-fra.com

Mise en veille prolongée - Clés étrangères au lieu d'entités

Actuellement, Hibernate me permet de charger des objets définis par des relations * -à-un directement avec

entity1.getEntity2()

Est-il possible d'obtenir la clé étrangère au lieu de l'objet?

L'approche actuelle que je vois consiste à ajouter un complément à ma cartographie:

@JoinColumn(name="message_key")
@ManyToOne(targetEntity=Message.class,fetch=FetchType.LAZY)
private Message message;  //these lines currently exist

@Column(name="message_key")
private Long message_fk; //the idea is to add those 2 lines

Existe-t-il une meilleure approche pour obtenir la clé étrangère, ou est-ce la seule?

45
iliaden

Oui, tu peux faire ça. Vous avez juste besoin de préciser pour hibernate lequel est le mappage qu'il est censé maintenir, comme ceci:

@Column(name="message_key", updatable=false, insertable=false)
private Long message_fk;
44
Affe

Si vous voulez toujours une référence à votre entité mais ne voulez pas la charger à partir de la base de données juste pour obtenir la clé étrangère, votre approche est la bonne. Ajoutez insertable et updatabale = false à l'attribut Column pour éviter de perdre la référence correcte à une entité.

@JoinColumn(name = "message_key")
@ManyToOne(targetEntity = Messages.class, fetch = FetchType.LAZY)
private Messages message;

@Column(name = "message_key", insertable = false, updatable = false)
private Long message_fk;
15
Marcelo

En fait, c'est le comportement Hibernate par défaut de charger uniquement la clé étrangère au lieu de l'objet message si le FetchType est LAZY. C'est pourquoi il existe des proxys pour les objets à charger lorsque vous spécifiez LAZY FetchType.

La clé étrangère n'est pas directement visible, mais il s'agit bien sûr de la clé de l'objet à l'extrémité "une" de la relation OneToMany.

Cependant, avec un type d'accès basé sur un champ (par exemple, dans votre cas, où des annotations sont placées sur des champs), il existe un problème d'hibernation non résolu: Hibernate charge tout l'objet derrière le proxy à partir de la base de données. ( http://blog.xebia.com/2009/06/13/jpa-implementation-patterns-field-access-vs-property-access/ )

Ma suggestion concrète serait (comme, par exemple, la "bonne" réponse n'a pas fonctionné dans mon cas):

  • Utilisez directement l'objet de message, car Hibernate ne le chargera que si des données sans clé étrangère sont nécessaires. Ne spécifiez pas de champ supplémentaire pour la clé étrangère.
  • Basculez la classe pour utiliser l'accès aux propriétés, c'est-à-dire définir les getters et setters, et placez vos annotations des champs vers les getters.
4
RobertG
Long fk = entity1.getEntity2().getId();

Cela devrait fonctionner. Cela ne fonctionnerait pas seulement si vous avez des clés composites référencées en tant que clés étrangères, mais votre solution ne fonctionnerait pas non plus dans ce cas. Compte tenu de ma solution, même une clé composite ne serait pas si moche.

Long fkField1 = entity1.getEntity2().getCol1();
String fkField2 = entity1.getEntity2().getCol2();

Quelque chose comme ça fonctionnera.

EDIT: En pensant davantage à votre solution proposée, cela ne fonctionnerait pas de toute façon car Hibernate essaie déjà de créer automatiquement un champ FK pour une relation mappée, donc définir un autre @Column essaierait simplement de se lier à une seconde colonne du même nom.

1
Jesse Webb