JPA / Hibernate: @ManyToOne et @ OneToOne relationships tagged as FetchType.Paresseux et optionnel = false Ne pas charger paresseusement sur em.trouver()?

j'ai l'entité ci-dessous (uniquement les mappages):

@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Integer id;

    @Column
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)                 // lazy XToOne
    @JoinColumn(name = "user_id", referencedColumnName = "person_id")
    private User user;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
    private Group group;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY) // lazy XToOne
    private Tendering tendering;

    ...
}

notez les commentaires ci-dessus: il y a trois @XToOne relations avec d'autres entités:

Utilisateur (un SecurityIdentity sous-classe avec un simple ID PK, référencé par PQ, représentant le propriétaire):

@Entity
@Table(name = "Users")
@DiscriminatorValue(value = "user")
public class User extends SecurityIdentity
{
    @Column
    private String name;

    @OneToMany(mappedBy = "user")
    private Set<PQ> pqs = new HashSet<PQ>();

    ...
}

Groupe (aussi une sous-classe SecurityIdentity avec un simple ID comme PK, fait référence au PQ pour représenter un ensemble d'utilisateurs qui peuvent interagir avec qui PQ):

@Entity
@Table(name = "Groups")
@DiscriminatorValue(value = "group")
public class Group extends SecurityIdentity
{
    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pq_id", referencedColumnName = "id")
    private PQ pq;

    ...
}

appel d'Offres:

@Entity
@Table(name = "Tenderings")
public class Tendering implements Serializable
{
    @Id
    @Column(name = "pq_id", insertable = false, updatable = false)
    private Integer pqId;

    @Column(name = "external_code")
    private String externalCode;

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "pq_id", referencedColumnName = "id")
    private PQ pq;

    ...
}

ne vous méprenez pas sur les groupes et les utilisateurs qui partagent des identifiants, traitez-les simplement comme de simples identifiants. Un appel d'offres n'est qu'un document distinct (un à un).

Comme vous pouvez le voir il y a trois @XToOne relations sur l'entité PQ, qui, si aucun type fetch n'était défini, serait chargé avec empressement (par défaut JPA). Donc pour empêcher cela j'ai étiqueté tout @XToOne relations FetchType.LAZY.

maintenant quand vous utilisez

em.find(PQ.class, someExistingId);

je l'Hibernation de sortie:

23:53:55,815 INFO  [stdout] Hibernate: select pq0_.id as id291_0_, pq0_.description as descript2_291_0_, pq0_.name as name291_0_, pq0_.submission_date as submission4_291_0_, pq0_.user_id as user5_291_0_ from PQs pq0_ where pq0_.id=?
23:53:55,818 INFO  [stdout] Hibernate: select user0_.id as id280_0_, user0_1_.identity_type_id as identity2_280_0_, user0_.is_enabled as is1_297_0_, user0_.name as name297_0_, user0_.password as password297_0_, user0_.person_id as person5_297_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
23:53:55,821 INFO  [stdout] Hibernate: select group0_.id as id280_0_, group0_1_.identity_type_id as identity2_280_0_, group0_.pq_id as pq2_281_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?
23:53:55,823 INFO  [stdout] Hibernate: select tendering0_.pq_id as pq1_296_0_, tendering0_.binary_file as binary2_296_0_, tendering0_.customer_id as customer6_296_0_, tendering0_.description as descript3_296_0_, tendering0_.external_code as external4_296_0_, tendering0_.title as title296_0_ from Tenderings tendering0_ where tendering0_.pq_id=?

les trois sélections supplémentaires proviennent des relations @XToOne (comme décrit à de nombreux endroits sur le net). La source que j'étais en train de regarder est la plupart du temps ceci:

Faire un OneToOne-rapport lazy

comme il est mentionné ici, le @ManyToOne relation User user should not be fetched:

@ManyToOne(fetch=FetchType.LAZY) devrait fonctionner parfaitement.

... ici, la relation de l' PQUtilisateur, mais tiré comme vous pouvez le voir de la select user0_.id as id280_0_, ... déclaration...

Pour les deux autres Group group et Tendering tendering, les @OneToOneinverse mappings, les clés étrangères renvoient à la PK (ID) de la table PQs, ce qui donne la même correspondance dans l'entité PQ.

notez que les trois relations ne sont pas optionnels: un PQ a toujours un propriétaire (Utilisateur), et un PQ est toujours référencé par un appel d'offres et une entité de groupe. Je n'avais pas encore modélisé ça à JPA...

donc, en ajoutant optional = false pour les trois relations du PQ entité:

@Entity
@Table(name = "PQs")
public class PQ implements Serializable
{
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column
    private Integer id;

    @Column
    private String name;

    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "user_id", referencedColumnName = "person_id")
    private User user;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
    private Group group;

    @OneToOne(mappedBy = "pq", fetch = FetchType.LAZY, optional = false)
    private Tendering tendering;

    ...
}

... J'ai le Hibernate de sortie:

00:47:34,397 INFO  [stdout] Hibernate: select pq0_.id as id361_0_, pq0_.description as descript2_361_0_, pq0_.name as name361_0_, pq0_.submission_date as submission4_361_0_, pq0_.user_id as user5_361_0_ from PQs pq0_ where pq0_.id=?
00:47:34,410 INFO  [stdout] Hibernate: select user0_.id as id350_0_, user0_1_.identity_type_id as identity2_350_0_, user0_.is_enabled as is1_367_0_, user0_.name as name367_0_, user0_.password as password367_0_, user0_.person_id as person5_367_0_ from Users user0_ inner join SecurityIdentities user0_1_ on user0_.id=user0_1_.id where user0_.person_id=?
00:47:34,413 INFO  [stdout] Hibernate: select group0_.id as id350_0_, group0_1_.identity_type_id as identity2_350_0_, group0_.pq_id as pq2_351_0_ from Groups group0_ inner join SecurityIdentities group0_1_ on group0_.id=group0_1_.id where group0_.pq_id=?

Remarque, que je n'ai été jouer avec le optional = false sur l'entité PQ, car c'est celle que j'utilise dans em.find(...). (Si ce n'est pas suffisant, veuillez de m'éclairer.)

Ma question est maintenant deux fois:

  1. Pourquoi @ManyToOneUser entité extraite avec impatience (étant donné que c'était, dit-on travailler paresseusement, voir Faire un OneToOne-rapport lazy)?
  2. Pourquoi est seulement le OneToOne relation Tendering entité laissée pour compte? Est-ce parce que le Tendering références d'entité du PQ PK colonne de PK lui-même (@IdTendering),Group entité doesn't (relation régulière avec le PK du PQ)?

Quel est le problème? Comment puis-je rendre ces relations non-optionnelles paresseuses? (sans code-instrumentation ou autres hacks, juste des annotations simples...)

je sais que la paresse n'est qu'une indication pour le fournisseur JPA de faire quelque chose à propos de la paresse du chargement ou non, mais dans ce cas, il semble que quelque chose d'autre ne va pas (car une partie de cela fonctionne).

PS: J'utilise Hibernate 4.0 BETA, la version qui vient avec JBoss 7.0.0.Final ainsi que les annotations JPA seulement (les ci-dessus sont tous compatibles JPA 1.0).

15
demandé sur Community 2011-10-12 03:30:34

4 réponses

Salut, je ne suis pas sûr de JPA, mais pour many-to-one et one-to-one mappages les valeurs paresseuses qui sont supportées hibernent sont proxy, no-proxy et false dont false est par défaut. Vérifiez cette partie de la DTD

lazy="proxy|no-proxy|false"

et vous pouvez le vérifier Lien. Je pense que cela répond à votre première question.

2
répondu M.J. 2011-10-18 18:44:49

il y a des différences entre les annotations hibernate et les annotations jpa et autant que je sache, hibernate est chargé par défaut sauf dans certains cas. voici une brève discussion:

http://community.jboss.org/wiki/AShortPrimerOnFetchingStrategies

2
répondu BikeHikeJuno 2011-12-06 04:31:29

* la relation ToOne implique qu'il doit y avoir (proxy) bean après l'initialisation de l'objet, qui va déclencher select (vous le voyez) dès qu'il est accédé d'une manière ou d'une autre Êtes-vous sûr de ne rien faire avec des objets qui pourraient forcer le chargement?

0
répondu Konstantin Pribluda 2011-10-21 08:31:12

Hi Kawu vous montrez des SELECTs supplémentaires parce qu'ils vont exécuter des SELECTs pour toutes les entités impliquées, essayez D'utiliser FetchType.PARESSEUX pour défaut Un-à-Plusieurs et dans la plupart des cas, de sorte qu'à l'aide de FETCH JOINDRE pour obtenir des résultats.

j'espère aider, en u, ou quelqu'un qui ont besoin de cette information

0
répondu antonio 2016-05-08 15:30:06