É possível ter a chave estrangeira imposta sem mapeamento de objeto para objeto?
-
22-09-2019 - |
Pergunta
Supondo que os seguintes mapeamentos sejam fornecidos:
<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
}
É possível mudar o mapeamento de hibernato para que A chave estrangeira ainda é aplicada e criada por Hibernate na startup, mas aula A
pareceria o seguinte:
public class A {
private long id;
private long idOfB;
// getters and setters skipped
}
Eu entendo que se eu converter <many-to-one...
dentro de <property...
Isso funcionaria, mas a chave estrangeira não seria aplicada pelo banco de dados.
Eu preciso fazer isso porque objeto B
pode (ou não) ser inicializado separadamente, o que às vezes causaorg.hibernate.LazyInitializationException: could not initialize proxy - no Session
exceções a ocorrer quando a.getB()
é chamado. Eu preferiria tê -lo como um long idOfB
e carregar um objeto inteiro sempre que for necessário; Isso também tornaria o carregamento do objeto A
mais rápido.
Eu acredito que minha pergunta é muito semelhante a Este, no entanto, a solução oferecida (para usar carregamento preguiçoso) não é apropriado no meu caso, mesmo que eu ligue a.getB().getId()
, Eu pegaria LazyInitializationException
Considerando que se eu ligar a.getIdOfB()
Eu não faria.
Muito obrigado antecipadamente.
Solução
Como dito
Eu entendo que se eu converter Mas a chave estrangeira não seria aplicada pelo banco de dados.
Então, meu conselho é: use ambos
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>
Observe quando duas propriedades compartilham a mesma coluna, Você tem que colocar configurações sobre isso em apenas uma propriedade. Caso contrário, o Hibernate reclamará alguns erros. Ele explica por que eu defino update = "false" e insert = "false" na propriedade EntityB.
Saudações,
Outras dicas
Você sempre pode criar a chave estrangeira DDL manualmente no seu arquivo hibernado hbm.xml:
<hibernate-mapping>
...
<database-object>
<create>[CREATE FK]</create>
<drop>[DROP FK]</drop>
</database-object>
</hibernate-mapping>
Você também pode procurar isso se diferentes dialetos precisarem ser suportados.
Verificação de saída 5.7. Objetos de banco de dados auxiliares
Outra abordagem que você pode adotar é definir o FK com seu mapeamento B, em vez do mapeamento A. Eu adicionei o código JPA, você teria que traduzir isso no seu arquivo de mapeamento de hibernato se você não estiver usando anotações.
@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 não seria assim:
@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;
}
}
Eu recomendo que você associe objetos a objetos para obter vantagens completas do Hibernate. Eu acho que o problema é a exceção que você recebe. Isso ocorre porque a sessão de hibernato já está fechada quando você tenta obter o objeto preguiçoso. Existem várias postagens neste blog que mostram respostas para esse problema, por exemplo, este:Texto do link.
Caso você esteja usando a primavera, você pode usar o OpenEntityManagerInViewFilter para que a sessão se mantenha aberta até que a exibição seja renderizada.