2011-10-11 12 views
15

Tengo el siguiente entidad (sólo asignaciones correspondientes se muestra):JPA/Hibernate: @ManyToOne y @OneToOne relaciones etiquetadas como FetchType.LAZY y opcional = falso no cargando perezosamente en em.find()?

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

    ... 
} 

nota de las observaciones anteriores: hay tres @XToOne relaciones con otras entidades:

usuario (una clase SecurityIdentity sub con un simple ID como PK, referenciado por PQ que representa el propietario):

@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>(); 

    ... 
} 

Grupo (una lso una subclase SecurityIdentity con una identificación simple como PK, hace referencia al PQ para representar un conjunto de usuarios que pueden interactuar con el 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; 

    ... 
} 

licitación:

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

    ... 
} 

no hacer confundirse acerca de los grupos y usuarios que comparten ID, solo trátelos como ID simples. Una licitación es solo un objeto de documento separado (uno a uno).

Como puede ver, hay tres relaciones @XToOne en la entidad PQ, que, si no se estableció un tipo de búsqueda, se cargarían con entusiasmo (valor predeterminado de JPA). Para evitar esto, etiqueté todas las relaciones @XToOne como FetchType.LAZY.

Ahora cuando se utiliza

em.find(PQ.class, someExistingId);

consigo la salida de Hibernate:

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=? 

Los tres SELECTs adicionales se derivan de las relaciones @XToOne (como se describe en muchos lugares en la red). La fuente que estaba buscando en su mayoría es la siguiente:

Making a OneToOne-relation lazy

Como se menciona allí, el @ManyToOne relación User user no debe ser exagerado:

@ManyToOne(fetch=FetchType.LAZY) debería funcionar bien.

... aquí la relación de PQ a usuario, pero es descabellada como se puede ver en la declaración select user0_.id as id280_0_, ... ...

Para los otros dos Group group y Tendering tendering, ambas @OneToOneinversa asignaciones, las claves foráneas hacen referencia a PK (ID) de la tabla PQs, lo que da como resultado el mismo mapeo en la entidad PQ.

Tenga en cuenta que las tres relaciones no son opcionales: una PQ siempre tiene un propietario (usuario), y una PQ siempre es referenciada por una licitación y una entidad de grupo. Simplemente no había modelado eso en JPA por encima todavía ...

Por lo tanto, cuando se añade optional = false a las tres relaciones de la entidad PQ:

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

    ... 
} 

... Me da la siguiente salida de Hibernate:

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=? 

Tenga en cuenta, que sólo he estado jugando con el optional = false en la entidad PQ, ya que este es el que uso en em.find(...). (Si esto no es suficiente, por favor me ilumine.)

Mi pregunta ahora es doble:

  1. ¿Por qué es el @ManyToOne a la entidad User fue a buscar ansiosamente (dado que es fue dice que está trabajando con pereza , ver Making a OneToOne-relation lazy)?
  2. ¿Por qué solo se obtiene la relación OneToOne con la entidad Tendering? ¿Es porque la entidad Tendering hace referencia a la columna PK de la PQ como un PK mismo (@Id en Tendering), que la entidad Group no tiene (relación regular con la PK de la PQ)?

¿Qué pasa? ¿Cómo hago perezosas estas relaciones no opcionales? (sin instrumentación de código u otros hacks, simplemente anotaciones ...)

Sé que lo PERDIDO es solo una pista para que el proveedor de JPA haga algo acerca de la carga diferida o no, pero en este caso parece como si algo más está mal (como parte de ello está funcionando).

PD: Estoy usando Hibernate 4.0 BETA, la versión que viene con JBoss 7.0.0.Final junto con las anotaciones JPA solamente (todas las anteriores son todas compatibles con JPA 1.0).

+0

Tal vez sea solo un error. Ver https: // hibernate.onjira.com/browse/HHH-3930, que es similar. –

Respuesta

2

Hola no estoy seguro acerca de la APP, pero para many-to-one y one-to-one asignaciones de los valores perezosos que son compatibles con hibernación son proxy, no-proxy y false de los cuales falsa es por defecto. comprobar esta parte de la DTD

lazy="proxy|no-proxy|false"

y se puede comprobar esto Link. Creo que esto responde su primera pregunta hasta cierto punto.

+0

El valor predeterminado para 'lazy =" proxy | no-proxy | false "' es proxy, como está escrito en el enlace que ha publicado (ver 12): "flojo (opcional - predeterminado a proxy): por defecto, asociaciones de punto único son proxies. lazy = "no-proxy" especifica que la propiedad debe buscarse perezosamente cuando se accede por primera vez a la variable de instancia. Esto requiere instrumentación de bytecode en tiempo de construcción. lazy = "false" especifica que la asociación siempre será buscada con entusiasmo. " – Kawu

0

* La relación ToOne implica que debe haber bean (proxy) después de la inicialización del objeto, que activará select (lo está viendo) tan pronto como se acceda de alguna manera ¿está seguro de que no hace nada con objetos que podrían forzar ¿cargando?

0

Hola Kawu le muestre SELECTs adicionales porque se ejecutará selecciona para todas las entidades involucradas, trate de usar FetchType.LAZY por defecto Uno-a-muchos, y en la mayoría de los casos por lo que usar JOIN FETCH para obtener resultados

Espero ayudarte o alguien que necesite esta información

Cuestiones relacionadas