ti-enxame.com

Qual é a diferença entre NHibernate Query <> vs QueryOver <>?

Acabei de começar com NHibernate (usando SQLite) no meu projeto atual e usei principalmente Query<>, porque eu estava familiarizado com consultas de banco de dados no Linq.

Quando fui confrontado com algumas consultas mais complexas, fiz algumas pesquisas sobre QueryOver<> e imaginou que deveria ser favorecido em vez de Query<> porque "A sintaxe do QueryOver é específica do NH". Além disso, parece não haver nada que Query<> pode fazer isso QueryOver<> não pode realizar.

Então comecei a substituir todos os usos de Query<> adequadamente. Não demorou muito para que eu tivesse o primeiro "problema" em que use Query<> parecia apenas mais conveniente. Exemplo (selecione o valor mais alto da coluna CustomNumber na tabela BillingDataEntity):

int result = Session.Query<BillingDataEntity>().Select(x => x.CustomNumber).OrderByDescending(a => a).FirstOrDefault();
int result = Session.QueryOver<BillingDataEntity>().Select(x => x.CustomNumber).OrderBy(a => a.CustomNumber).Desc.Take(1).SingleOrDefault<int>();

O que eu não gosto é a necessidade de converter explicitamente o resultado para int e que a versão Query <> seja apenas mais fácil de ler. Estou entendendo a consulta totalmente incorreta ou em outras palavras: Existe uma maneira melhor de fazer isso?

Dei uma olhada na saída SQL gerada:

NHibernate: select billingdat0_.CustomNumber as col_0_0_ from "BillingDataEntity" billingdat0_ order by billingdat0_.CustomNumber desc limit 1
NHibernate: SELECT this_.CustomNumber as y0_ FROM "BillingDataEntity" this_ ORDER BY this_.CustomNumber desc limit @p0;@p0 = 1 [Type: Int32 (0)]

O que exatamente eu estou olhando? Essa é a consulta "interna" (dependente do método) que o NHibernate traduz ainda mais na consulta real do banco de dados?

28
Rev1.0

Há muitas respostas sobre QueryOver versus Query aqui no Stackoverflow, mas em poucas palavras: -

QueryOver é uma versão fortemente tipada dos Critérios e é mais específica do NHibernate. Praticamente tudo o que você pode fazer no ICriteria pode ser feito com o QueryOver. Nos dias dourados do ICriteria NH2, você sempre teve que lançar, portanto, é por isso que agora você precisa converter no final da cadeia de volta a um int.

LINQ (Query) é um método de consulta padrão que funciona no IQueryable que não precisa de referências explícitas ao NHibernate e pode ser considerado mais independente de ORM e, portanto, segue o padrão linq. Como você apontou corretamente, não é necessário converter para um int, pois você seleciona no resultado o númeroNúmero.

Eu ficaria muito surpreso com o seu exemplo simples se o SQL gerado fosse muito diferente.

Eu era um grande fã de QueryOver, mas como o provedor Linq está ficando mais maduro, em seguida, 95% das minhas consultas eu uso Query, mas para algumas coisas específicas do Nhibernate eu recorro a QueryOver. De qualquer maneira, recomendo usar uma ferramenta de criação de perfil para ver com o que você pode viver.

Refs: tradeoffs ou versus e versus

34
Rippo

Sobre sua versão do QueryOver, eu teria escrito:

int result = Session.QueryOver<BillingDataEntity>()
               .Select(Projections.Max<BillingDataEntity>(x => x.CustomNumber))
               .SingleOrDefault<int>();

Parece bastante legível, e o SQL resultante seria algo como:

SELECT max(this_.CustomNumber) as y0_ FROM "BillingDataEntity" this_

Espero que isso ajude

2
jbl