Eu tinha o seguinte código hoje pra otimizar (extraído de um Controller do projeto que estou trabalhando):
[Layout("popup")]
public void Observacoes([ARFetch] Pedido pedido, [ARFetch] Fornecedor fornecedor) {
SimpleQuery
if (fornecedor == null) {
consulta = new SimpleQuery
from ObservacaoPedido obs
where obs.Pedido = ?
order by obs.CriacaoData
", pedido);
}
else {
consulta = new SimpleQuery
from ObservacaoPedido obs
where obs.Pedido = ? and obs.Fornecedor = ?
order by obs.CriacaoData
", pedido, fornecedor);
}
IEnumerable
PropertyBag.Add("fornecedor", fornecedor);
PropertyBag.Add("observacoes", observacoes);
}
Qual era o problema dele? A princípio, nenhum... Mas o NHibernate tem uma certa particularidade: quando o carregamento de objetos veio de uma consulta HQL, ele não cria proxies para os objetos (ou seja, sem lazy-loading para relacionamentos muitos-para-um), e só carrega exatamente o que diz minha consulta. O resultado é um turbilhão de consultas sendo enviadas ao banco, para carregar os dados que "faltaram"... Mesmo que eu não use eles.
Introduzindo, então, o DetachedCriteria:
public void Observacoes([ARFetch] Pedido pedido, [ARFetch] Fornecedor fornecedor) {
QueryBuilder
Where.ObservacaoPedido.Pedido == pedido;
DetachedCriteria crit = q;
crit.SetResultTransformer(new DistinctRootEntityResultTransformer());
crit.SetFetchMode("Anexos", FetchMode.Eager);
crit.SetFetchMode("Anexos.Arquivo", FetchMode.Eager);
IEnumerable
ObservacaoPedido.List(crit, OrderBy.ObservacaoPedido.CriacaoData);
PropertyBag.Add("pedido", pedido);
PropertyBag.Add("fornecedor", fornecedor);
PropertyBag.Add("observacoes", observacoes);
}
O código, menor, ficou até um pouco mais claro, apesar de ter ficado mais arcano, expondo mais o NHibernate. Teria ficado mais ainda, se eu não tivesse utilizado o NHQG do Ayende para gerar o DetachedCriteria.
O resultado? Apenas uma consulta sendo enviada ao banco, e o tempo de carregamento de uma tela baixou de 3s pra 0,4s.