¿Es posible tener la clave externa forzada sin mapeo objeto-objeto?
-
22-09-2019 - |
Pregunta
Suponiendo las siguientes asignaciones:
<class name="A" table="a_table">
<id name="id"/>
<many-to-one name="entityB" column="fk_B" not-null="false" unique="true"/>
</class>
<class name="B" table="b_table">
<id name="id"/>
</class>
clase Java:
public class A {
private long id;
private B entityB;
// getters and setters skipped
}
¿Es posible cambiar el mapeo de Hibernate para que clave externa todavía se aplica y creado por Hibernate en el inicio , pero A
clase se vería como el siguiente:
public class A {
private long id;
private long idOfB;
// getters and setters skipped
}
Yo entiendo que si me convierto en un <many-to-one...
<property...
esto funcionaría, pero la clave externa no se aplicarían por la base de datos.
Necesito hacer esto porque podría objetar B
(o no) ser inicializado por separado que a veces causas
excepciones a org.hibernate.LazyInitializationException: could not initialize proxy - no Session
se producen cuando a.getB()
se llama. Yo preferiría tenerlo como long idOfB
y cargar objeto entero siempre que sea necesario; Esto también haría que la carga de A
objeto más rápido.
Creo que mi pregunta es muy similar a éste, sin embargo, la solución que se ofrece (para usar la carga diferida) no es apropiado en mi caso, ya que incluso si llamo a.getB().getId()
, me gustaría obtener LazyInitializationException
mientras que si llamo a.getIdOfB()
que no lo haría.
Muchas gracias de antemano.
Solución
Como dijo
Yo entiendo que si convierto
, pero la clave externa no se aplicarían por la base de datos.
Así que mi consejo es: utilizar tanto
public class EntityA {
private Integer idOfB;
private EntityB entityB;
// getter's and setter's
}
y
<class name="A" table="a_table">
<id name="id"/>
<property name="idOfB" column="fk_B" not-null="false" unique="true"/>
<many-to-one name="entityB" update="false" insert="false" column="fk_B"/>
</class>
Aviso cuando dos propiedades comparten la misma columna, usted tiene que poner los ajustes de ello en una sola propiedad . De lo contrario, Hibernate se quejan algunos errores. Esto explica por qué yo defino update = "false" e inserte = "false" en la propiedad entityB.
cordiales,
Otros consejos
Siempre se puede crear la clave externa DDL manualmente en su archivo hbm.xml de hibernación:
<hibernate-mapping>
...
<database-object>
<create>[CREATE FK]</create>
<drop>[DROP FK]</drop>
</database-object>
</hibernate-mapping>
También puede alcance este caso diferentes dialectos tienen que ser apoyada.
Otro enfoque que podría tomar es definir el FK con su asignación B en vez de la asignación A. He añadido el código de la APP, que tendría que traducir esto a su archivo de asignación de hibernación si no está utilizando anotaciones.
@Entity
public class B
{
private long id;
private List<A> aList;
@Id
@Column( name = "ID" )
public long getId()
{
return id;
}
@OneToMany
@JoinColumn( name = "B_ID" )
public List<A> getAList()
{
return aList;
}
public void setId( long id )
{
this.id = id;
}
public void setAList( List<A> aList )
{
this.aList = aList;
}
}
A.java no se vería así:
@Entity
public class A
{
private long id;
private long idOfB;
@Id
@Column( name = "ID" )
public long getId()
{
return id;
}
@Column( name = "B_ID" )
public long getIdOfB()
{
return idOfB;
}
public void setId( long id )
{
this.id = id;
}
public void setIdOfB( long idOfB )
{
this.idOfB = idOfB;
}
}
Te recomiendo a los objetos asociados a objetos para conseguir ventajas completas de hibernación. Creo que el problema es la excepción que se obtiene. Esto se debe a sesión de Hibernate ya está cerrado cuando intenta obtener el objeto perezoso. Hay varios puestos en este blog que muestran respuestas a este problema, por ejemplo ésta: texto.
En caso de que esté usando primavera se puede utilizar OpenEntityManagerInViewFilter así, mantendrá abierta la sesión hasta que la vista es renderes.