Hibernate – How to force eager loading in HQL

annotationseager-loadinghibernatehql

I'm trying to force an HQL to eager load all the Lazy properties.
Using FETCH gives me the "multiple bags" exception and I can't change it to Set as they're referenced elsewhere. I tryed other mapping Annotations but no luck.
The "FETCH ALL PROPERTIES" is ignored and nothing is loaded. I never understood what it really does. Obviously when JSF tries to read the List I get the "cannot initialize lazy List. Connection closed"

I'm using Hibernate 4.0.
So here's my HQL query:

Select r from Responsavel r FETCH ALL PROPERTIES 
where r.unidadeEmpresarial.id = :idUnidade

And here's my model class:

public class Responsavel {

@Id
@SequenceGenerator(name = "SQ_RESPONSAVEL_GENERATOR", sequenceName = "SE_RESPONSAVEL", allocationSize = 1)
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "SQ_RESPONSAVEL_GENERATOR")
@Column(name = "SQ_RESPONSAVEL")
private Long id;

@Temporal(TemporalType.DATE)
@Column(name = "DT_FIM")
private Date dataFim;

@NotNull
@Temporal(TemporalType.DATE)
@Column(name = "DT_INICIO")
private Date dataInicio;

@Temporal(TemporalType.DATE)
@Column(name = "DT_NASCIMENTO")
private Date dataNascimento;

@Type(type = "org.hibernate.type.NumericBooleanType")
@Column(name = "IN_PODER_ADM_REPRES")
private Boolean temPoderAdministrativo;

@Column(name = "NO_RESPONSAVEL")
private String nome;

@Column(name = "NU_CPF_CNPJ_RESPONSAVEL")
private String numeroCpfCnpj;

@NotNull
@Enumerated(EnumType.STRING)
@Column(name = "TP_PESSOA")
private String tipoPessoa;

@ManyToOne
@JoinColumn(name = "SQ_PAIS")
private Pais pais;

@Column(name = "VL_CAPITAL_SOCIAL")
private BigDecimal valorCapitalSocial;

@Column(name = "PC_CAPITAL_SOCIAL")
private BigDecimal percentualCapitalSocial;

@ManyToOne
@JoinColumn(name = "SQ_UNIDADE_EMPRESARIAL")
private UnidadeEmpresarial unidadeEmpresarial;

@OneToMany(mappedBy = "responsavel", fetch = FetchType.LAZY)
@Fetch(FetchMode.SUBSELECT)
private Set<ResponsavelQualificacaoResponsavel> listaResponsavelQualificacaoResponsavel;

@OneToMany(mappedBy = "responsavel")
private List<Representante> representantes;

@OneToMany(mappedBy = "responsavel")
private List<ContatoResponsavel> contatoResponsavel;

@OneToMany(mappedBy = "responsavel", cascade = CascadeType.ALL)
private List<EnderecoResponsavel> enderecoResponsavel;

}

Thanks

Best Answer

If you are getting the multiple bags exception, then it is because Hibernate cannot get all of your collections at once. You should pick a collection you wish to select with your base query and do so with a join, then use Hibernate.initialize to obtain the remainder of the collections you require.

So it would look like this (I'm leaving off the select, since it isn't required):

from Responsavel r 
join fetch pais p
join fetch unidadeEmpresarial u
join fetch representantes s
where r.unidadeEmpresarial.id = :idUnidade

You can experiment with which ones to include. What's left, requires initialization if you wish to detach from the Hibernate session to, for example, use the collections in the front-end or in a service class.

Hibernate.initialize(listaResponsavelQualificacaoResponsavel);
Hibernate.initialize(contatoResponsavel);
Hibernate.initialize(enderecoResponsavel);

If you will be remaining the session, then no need to initialize, they will initialize on demand (though this could lead to a performance issue depending on your use case).

Related Topic