Um dos recursos que encontramos no NHibernate para executar queries nos nossos objetos é a HQL, que é simples e sua curva de aprendizado é bem rápida, já que ela tem uma sintaxe muito semelhante ao nosso SQL Ansi. Você poderá usar HQL em 80% de suas queries, mas em casos específicos necessitamos de outro recurso também muito eficiente e bem legal. São as Criteria Queries.
Com Criteria Queries podemos fazer queries programaticamente, com uma interface fluente nos nossos objetos do Nhibernate.
Com HQL e com Criteria Queries podemos fazer a mesma coisa, porém ao lermos nosso código teremos percepções diferentes. Para demonstrarmos o uso de NHibernate ResultTransform vou fazer as nossas queries das duas maneiras, com HQL e com Criteria Queries, assim vocês podem ter uma melhor visualização do que é mais legal para vocês trabalharem.
E em alguns casos, o resultado de nossas queries pode ser passado com através de um DTO, ou seja, uma classes de Data Transfer Object.
E em que caso podemos usar uma classe DTO?
Imagine que temos uma entidade de histórico de visitação de seu site.

Em qualquer relatório da nossa classe histórico para demonstrarmos a quantidade de acessos, certamente precisaremos agrupar os dados do histórico, por exemplo, agrupado por data, horários, ip, etc. Em qualquer um desses casos, um valor que será importante nesse agrupamento é a quantidade de registros que contem em cada grupo, de que adianta agruparmos os históricos do dia X sem sabermos a quantidade de acessos não é mesmo.
Então podemos “transformar” nosso resultado em uma classe fora do domínio de nossa aplicação, ou seja, uma classe DTO apenas para passarmos os dados do relatório. Vejam um exemplo abaixo de uma classe DTO:

Com isso, iriamos facilitar o acesso aos dados das nossas queries.
E como transformarmos nossos resultados? Com NHibernate ResultTransform. Esse recurso é pouco documentado e só achamos bons exemplos em blogs.
Vamos a um exemplo. Vamos agrupar por dias:
Em HQL:
IList histoticos = session.CreateQuery("select h.Ip, count(*) from Historico h group by h.Ip").List();
Com Criteria Queries
IList historicos = session.CreateCriteria(typeof(Historico))
.SetProjection(Projections.ProjectionList()
.Add(Projections.RowCount())
.Add(Projections.GroupProperty("Ip"))
).List();
Vejam nosso objeto “históricos” na nossa janela de “Locals” do Visual Studio, o resultado da nossa query.

As propriedades do nosso objeto são índices de arrays e para trabalhar dessa forma, podemos encontrar algumas dificuldades. Para transformarmos esse resultado em um objeto da classe HistoricoDTO usamos o ResultTransfom. Vamos a ele então.
Para transformarmos o nosso objeto acima em HistoricoDTO, iremos dar um “apelido” (alias) a nossas projeções, para que assim, o NHibernate “transforme” o resultado da query em HistoricoDTO.
Vamos ao HQL com nossos “apelido” (alias) as propriedades que iremos gerar:
IList criterio = session.CreateQuery("select h.Ip as IP, count(*) as Qnt from Historico h group by h.Ip")
.SetResultTransformer(NHibernate.Transform.Transformers.AliasToBean(typeof(HistoricoDTO))).List();
Aqui encontramos nossa primeira limitação no HQL. O HQL não suporta “apelidos” (alias) em suas projeções, por isso agora, recorremos ao Criteria Queries que suporta alias. Vejam como fica nosso código:
IList historicos = session.CreateCriteria(typeof(Historico))
.SetProjection(Projections.ProjectionList()
.Add(Projections.RowCount(), "QuantidadeDeAcessos")
.Add(Projections.GroupProperty("Ip"), "DescricaoDoGrupo")
).SetResultTransformer(Transformers.AliasToBean(typeof(HistoricoDTO))).List();
A segunda sobrecarga do método Add recebe uma string de Alias, que deve ser igual ao nome da propriedade de nossa DTO que desejamos “mapear”. Veja que antes de CreateCriteria retornar uma List() ele executa o método SetResultTransformer, que é onde indicamos a forma de “transformação” do resultado no objeto DTO. No nosso caso, indicamos o método estático da classe Transformer (namespace NHibernate.Transform) chamado AliasToBean, ou seja, “Apelido para Bean” (herança do irmão mais velho, o Hibernate escrito em Java). Esse Transformers.AliasToBean(typeof(HistoricoDTO)) portanto indica ao “transformador” do NHibernate usar o apelido da projeção como o nome da propriedade do objeto que passamos em typeof(HistoricoDTO).
Vejam como nosso objeto ficou na janela Locals:

Bem melhor agora, não é? Bem, vamos melhorar mais um pouco. Da forma que está, sempre necessitaríamos fazer um cast para trabalharmos com cada item da lista historicos, então para isso vamos deixar nossos amigos do Java com um pouco de inveja, usando o poder do Generics. Em NHibernate podemos retornar List() e também List<T>(). E isso é muito simples, vejam:
IList<HistoricoDTO> historicos = session.CreateCriteria(typeof(Historico))
.SetProjection(Projections.ProjectionList()
.Add(Projections.RowCount(), "QuantidadeDeAcessos")
.Add(Projections.GroupProperty("Ip"), "DescricaoDoGrupo")
).SetResultTransformer(Transformers.AliasToBean(typeof(HistoricoDTO))).List<HistoricoDTO>();
Pronto, agora não precisamos mais de casts em cada item de historicos.
Estou disponibilizando o código fonte com algumas coisas para facilitar a vida nos testes de quem quiser ver funcionando.
Junto do projeto existe um arquivo Default.aspx que vocês devem executar para criar a tabela e 1000 registros de testes que são criados usando números randomicos para a criação dos registros. O banco de dados que eu uso é o NHTestes, portanto, é só criarem o banco. O nome da instancia do SQL Server que eu uso é a “SQLExpress” em localhost, portanto o NHibernate vai tentar conectar em “localhost\sqlexpress”.
Ao executarem o “Default.aspx” e após gravar os 1000 registros de testes vai ser redirecionado para “NHibernateResultTransformer.aspx” onde vocês encontraram um menu para a chamada dos métodos e com os breakpoints já apontados.
Divirtão-se!
Fonte do Projeto de Exemplo
EDIT:
Para agrupamentos utilizando HQL, o Giovanni Bassi, membro fundador do Grupo .NET Architects, deu a opção de criarmos um construtor na classe HistoricoDTO que receba os valores DescricaoDoGrupo e QuantidadeDeAcessos. Nesse caso a HQL ficaria da seguinte maneira:
IList<HistoricoDTO> historicos = _session.CreateQuery("select new HistoricoDTO(h.Ip, count(h.Ip)) from Historico h group by h.Ip").List<HistoricoDTO>();
Notem que na HQL, instanciamos o objeto com a instrução new HistoricoDTO(h.Ip, count(h.Ip)) e no contrutor de HistoricoDTO é passado os valores no nosso agrupamento. Realmente é uma opção bem interessante dessa forma também. Porém necessitamos mapear nossa classe da seguinte forma:
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NHibernateResultTransformer.DomainModel" >
<import class="NHibernateResultTransformer.DomainModel.HistoricoDTO, NHibernateResultTransformer.DomainModel"/>
</hibernate-mapping>
[]´s
nhibernate resulttrasnformer hql criteria queries