En primer lugar, algunas aclaraciones a la respuesta de KLE :
La asociación uno a uno sin restricciones (anulable) es la única que no se puede representar sin instrumentación de bytecode. La razón de esto es que la entidad propietaria DEBE saber si la propiedad de asociación debe contener un objeto proxy o NULL y no puede determinar eso mirando las columnas de su tabla base debido a que normalmente se asigna uno a uno a través de PK compartida, por lo que tiene que ser traído con entusiasmo de todos modos haciendo que el proxy no tenga sentido. Aquí hay una explicación más detallada .
las asociaciones de muchos a uno (y uno a muchos, obviamente) no sufren este problema. La entidad propietaria puede verificar fácilmente su propio FK (y en el caso de uno a muchos, el proxy de colección vacío se crea inicialmente y se completa a pedido), por lo que la asociación puede ser perezosa.
Reemplazar uno a uno por uno a muchos nunca es una buena idea. Puede reemplazarlo con muchos a uno únicos, pero hay otras opciones (posiblemente mejores).
Rob H. tiene un punto válido, sin embargo, es posible que no pueda implementarlo dependiendo de su modelo (por ejemplo, si su asociación uno a uno es anulable).
Ahora, en cuanto a la pregunta original:
A) @ManyToOne(fetch=FetchType.LAZY)
debería funcionar bien. ¿Estás seguro de que no se sobrescribe en la consulta en sí? Es posible especificar join fetch
en HQL y / o establecer explícitamente el modo de búsqueda a través de Criteria API, que tendría prioridad sobre la anotación de clase. Si ese no es el caso y todavía tiene problemas, publique sus clases, consultas y el SQL resultante para una conversación más precisa.
B) @OneToOne
es más complicado. Si definitivamente no es anulable, vaya con la sugerencia de Rob H. y especifíquelo como tal:
@OneToOne(optional = false, fetch = FetchType.LAZY)
De lo contrario, si puede cambiar su base de datos (agregue una columna de clave externa a la tabla de propietarios), hágalo y asignela como "unida":
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name="other_entity_fk")
public OtherEntity getOther()
y en OtherEntity:
@OneToOne(mappedBy = "other")
public OwnerEntity getOwner()
Si no puede hacer eso (y no puede vivir con una búsqueda ansiosa), la instrumentación de código de bytes es su única opción. Sin embargo, tengo que estar de acuerdo con CPerkins , ¡si tienes 80! se une debido a las ansiosas asociaciones OneToOne, tienes mayores problemas que esto :-)
one-to-one
con una fórmula comoselect other_entity.id from other_entity where id = other_entity.id
. Por supuesto, esto no es ideal para realizar consultas.Para que la carga diferida funcione en asignaciones uno a uno anulables, debe dejar que Hibernate compile instrumentación de tiempo y agregue un
@LazyToOne(value = LazyToOneOption.NO_PROXY)
a la relación uno a uno.Ejemplo de mapeo:
Extensión de archivo Ant Build de ejemplo (para hacer la instrumentación de tiempo de compilación de Hibernate):
fuente
LazyToOneOption.NO_PROXY
y noLazyToOneOption.PROXY
?La idea básica detrás de los XToOnes en Hibernate es que no son flojos en la mayoría de los casos.
Una razón es que, cuando Hibernate tiene que decidir poner un proxy (con la identificación) o un valor nulo,
tiene que buscar en la otra tabla de todos modos para unirse. El costo de acceder a la otra tabla en la base de datos es significativo, por lo que también podría obtener los datos de esa tabla en ese momento (comportamiento no perezoso), en lugar de obtener eso en una solicitud posterior que requeriría un segundo acceso al misma mesa
Editado: para más detalles, consulte la respuesta de ChssPly76 . Este es menos preciso y detallado, no tiene nada que ofrecer. Gracias ChssPly76.
fuente
Aquí hay algo que me ha funcionado (sin instrumentación):
En lugar de usar
@OneToOne
en ambos lados, uso@OneToMany
en la parte inversa de la relación (la que tienemappedBy
). Eso hace que la propiedad sea una colección (List
en el ejemplo a continuación), pero la traduzco en un elemento en el captador, haciéndola transparente para los clientes.Esta configuración funciona de manera perezosa, es decir, las selecciones solo se realizan cuando
getPrevious()
ogetNext()
se llaman, y solo una selección para cada llamada.La estructura de la mesa:
La clase:
fuente
Como expliqué en este artículo , a menos que esté utilizando Bytecode Enhancement , no puede obtener perezosamente la asociación del lado primario
@OneToOne
.Sin embargo, la mayoría de las veces, ni siquiera necesita la asociación del lado de los padres si usa
@MapsId
el lado del cliente:Con
@MapsId
, laid
propiedad en la tabla secundaria sirve como clave primaria y clave externa para la clave primaria de la tabla primaria.Por lo tanto, si tiene una referencia a la
Post
entidad principal , puede buscar fácilmente la entidad secundaria utilizando el identificador de la entidad principal:De esta manera, no tendrá problemas de consulta N + 1 que podrían ser causados por la
mappedBy
@OneToOne
asociación en el lado primario.fuente
En las asignaciones XML de Hibernate nativas, puede lograr esto declarando una asignación uno a uno con el atributo restringido establecido en verdadero. No estoy seguro de cuál es el equivalente de anotación de Hibernate / JPA de eso, y una búsqueda rápida del documento no proporcionó respuesta, pero espero que eso te dé una pista para continuar.
fuente
@OneToOne(optional=false,fetch=FetchMode.LAZY)
Como ya explica perfectamente ChssPly76, los proxies de Hibernate no ayudan con asociaciones uno a uno sin restricciones (anulables), PERO hay un truco explicado aquí para evitar configurar la instrumentación. La idea es engañar a Hibernate porque la clase de entidad que queremos usar ya ha sido instrumentada: lo instrumenta manualmente en el código fuente. ¡Es fácil! Lo implementé con CGLib como proveedor de código de bytes y funciona (asegúrese de configurar lazy = "no-proxy" y fetch = "select", no "join", en su HBM).
Creo que esta es una buena alternativa a la instrumentación real (me refiero a la automática) cuando solo tiene una relación anulable de uno a uno que desea hacer vago. El principal inconveniente es que la solución depende del proveedor de código de bytes que esté utilizando, así que comente su clase con precisión porque podría tener que cambiar el proveedor de código de bytes en el futuro; por supuesto, también está modificando su bean modelo por una razón técnica y esto no está bien.
fuente
Esta pregunta es bastante antigua, pero con Hibernate 5.1.10, hay una nueva solución más cómoda.
La carga diferida funciona a excepción del lado primario de una asociación @OneToOne. Esto se debe a que Hibernate no tiene otra forma de saber si asignar un valor nulo o un proxy a esta variable. Más detalles puedes encontrar en este artículo
fuente
Si la relación no debe ser bidireccional, una @ElementCollection podría ser más fácil que usar una colección perezosa de One2Many.
fuente