E 'possibile avere chiave esterna forzata senza mapping object-to-oggetto?
-
22-09-2019 - |
Domanda
Supponendo i seguenti mappature sono forniti:
<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>
classe Java:
public class A {
private long id;
private B entityB;
// getters and setters skipped
}
E 'possibile cambiare la mappatura Hibernate in modo che chiave esterna è ancora applicata e creato da Hibernate all'avvio , ma di classe A
sarà simile come il seguente:
public class A {
private long id;
private long idOfB;
// getters and setters skipped
}
Capisco che se converto <many-to-one...
in un <property...
questo avrebbe funzionato, ma chiave esterna non sarebbe stato imposto dal database.
Ho bisogno di fare questo perché oggetto B
potrebbe (o non potrebbe) essere inizializzato separatamente che a volte le cause
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
a verificarsi quando si chiama a.getB()
eccezioni. Preferirei avere come un long idOfB
e caricare intero oggetto quando è necessario; questo sarebbe anche fare carico di oggetti A
più veloce.
Credo che la mia domanda è molto simile a questo , eppure la soluzione offerta (per usare lazy loading) non è appropriato nel mio caso, come anche se chiamo a.getB().getId()
, avrei avuto LazyInitializationException
mentre se chiamo a.getIdOfB()
non lo farei.
Grazie mille in anticipo.
Soluzione
Come detto
Capisco che se converto
ma chiave esterna non verrebbe applicato dal database.
Quindi il mio consiglio è: utilizzare entrambi
public class EntityA {
private Integer idOfB;
private EntityB entityB;
// getter's and setter's
}
E
<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>
Avviso quando due proprietà condividono la stessa colonna, devi mettere le impostazioni su di esso in una sola proprietà . In caso contrario, Hibernate si lamenterà alcuni errori. Ciò spiega perché i definisco aggiornamento = "false" e inserire = "false" in proprietà entityB.
saluti,
Altri suggerimenti
Si può sempre creare manualmente la chiave esterna DDL nel file hbm.xml hibernate:
<hibernate-mapping>
...
<database-object>
<create>[CREATE FK]</create>
<drop>[DROP FK]</drop>
</database-object>
</hibernate-mapping>
È anche possibile campo di applicazione questo se diversi dialetti devono essere supportati.
Un altro approccio si può prendere è quello di definire l'FK con la mappatura B piuttosto che la A mappatura. Ho aggiunto il codice di APP, che avrebbe dovuto tradurre questo al vostro file di mapping Hibernate, se non si sta usando le annotazioni.
@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 non sarebbe simile a questa:
@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;
}
}
Vi consiglio di associare oggetti a oggetti per ottenere vantaggi completi di Hibernate. Credo che il problema è l'eccezione che si ottiene. Questo perché la sessione Hibernate è già chiusa quando si tenta di ottenere l'oggetto pigro. Ci sono diversi messaggi in questo blog che mostrano le risposte a questo problema, per esempio questa: testo .
Nel caso in cui si sta utilizzando la primavera è possibile utilizzare OpenEntityManagerInViewFilter così la sessione continuano fino a che la vista è renderes.