Porque e como utilizar queries LINQ em um Pattern Repository


Então você decidiu adotar software patterns para melhoria no desenvolvimento de sistemas e acha que tudo estará resolvido!?

Montou uma framework própria baseada em bibliotecas existentes que obedece às N regras de separação de camada, desacopalhamentos e etc.


Então foi executar o sistema em produção e ele está uma lentidão que não consegue descobrir o motivo.


Considerando que o gargalo está ocorrendo nas consultas ao banco de dados, independente de qualquer framework de acesso a dados adotada, temos que tomar cuidado com o mapeamento dos campos de cada entidade e ainda, sabermos projetar as colunas que efetivamente iremos utilizar nas consultas, porque por padrão quando, por exemplo, vamos acessar a uma coleção para listar registros, todas as propriedades serão populadas pela projeção de todos os campos mapeados, exceção às propriedades 1-1, 1-n e n-n que trabalharão de acordo com a configuração de lazy load.


Como resultado uma consulta "simples" tipo:

var rotinaContabilCaixa = this.RotinasContabeisCaixa.ComTipoContabil(tipoContabil, planoContaContaContabil).Obter();


Gerará a seguinte query (obedecendo ao mapeamento existente - desnecessário expor):


select ROTINACONT0_.CODIGO as CODIGO16_0_, ROTINACONT0_.CODIGOPLANOCONTAS as CODIGOPL2_16_0_,
       PLANOCONTA1_.CODIGO as CODIGO128_1_, PLANOCONTA1_.CODIGOPLANOCONTAS as CODIGOPL2_128_1_,
       ROTINACONT0_.DTREG as DTREG16_0_, ROTINACONT0_.USOREG as USOREG16_0_, ROTINACONT0_.HORAREG as HORAREG16_0_,
       ROTINACONT0_.NOME as NOME16_0_, ROTINACONT0_.CODIGOTIPOCONTABIL as CODIGOTI7_16_0_,
       ROTINACONT0_.CODIGOCONTADEBITOPAGAMENTO as CODIGOCO8_16_0_, PLANOCONTA1_.NOME as NOME128_1_,
       PLANOCONTA1_.CODIGOCONTAMAE as CODIGOCO4_128_1_, PLANOCONTA1_.TIPO as TIPO128_1_,
       PLANOCONTA1_.NATUREZA as NATUREZA128_1_, PLANOCONTA1_.CODIGOREDUZIDO as CODIGORE7_128_1_,
       PLANOCONTA1_.CODRAUX as CODRAUX128_1_, PLANOCONTA1_.NIVEL as NIVEL128_1_,
       PLANOCONTA1_.CONTROLE as CONTROLE128_1_, PLANOCONTA1_.MOSTRANOBALANCO as MOSTRAN11_128_1_,
       PLANOCONTA1_.CODIGOPERMANENCIA as CODIGOP12_128_1_, PLANOCONTA1_.CODIGOAUXILIAR as CODIGOA13_128_1_,
       PLANOCONTA1_.DTREG as DTREG128_1_, PLANOCONTA1_.HORAREG as HORAREG128_1_, PLANOCONTA1_.USOREG as USOREG128_1_,
       PLANOCONTA1_.NAOINTEGRARCONTABILIDADE as NAOINTE17_128_1_, PLANOCONTA1_.NAOMOSTRARNODEREX as NAOMOST18_128_1_,
       PLANOCONTA1_.CONTAFIXA as CONTAFIXA128_1_, PLANOCONTA1_.CODIGODEORDEM as CODIGOD20_128_1_,
       PLANOCONTA1_.ATRIBUIRVALORDE as ATRIBUI21_128_1_, PLANOCONTA1_.NAOCONTABILIZARNOBANCO as NAOCONT22_128_1_,
       PLANOCONTA1_.TIPODEMOVIMENTO as TIPODEM23_128_1_, PLANOCONTA1_.COLUNAFLUXO as COLUNAF24_128_1_,
       PLANOCONTA1_.CONTAANTIGA as CONTAAN25_128_1_, PLANOCONTA1_.CONTAPARADIRF as CONTAPA26_128_1_,
       PLANOCONTA1_.CODIGOCONTAREDUTORA as CODIGOC27_128_1_,
       PLANOCONTA1_.LANCARCENTROCUSTOCONTABILIDADE as LANCARC28_128_1_,
       PLANOCONTA1_.LANCARATIVIDADECONTABILIDADE as LANCARA29_128_1_,
       PLANOCONTA1_.CADASTRAIMOBILIZADO as CADASTR30_128_1_, PLANOCONTA1_.DIRETAINDIRETA as DIRETAI31_128_1_,
       PLANOCONTA1_.CODIGOHISTORICO as CODIGOH32_128_1_, PLANOCONTA1_.CONTAQDFINANCEIRAVEMDOPRODUTO as CONTAQD33_128_1_,
       PLANOCONTA1_.TIPOLANCAMENTOORCAMENTO as TIPOLAN34_128_1_, PLANOCONTA1_.FORMACALCULOFOLHA as FORMACA35_128_1_,
       PLANOCONTA1_.FORMULACALCULOORCAMENTO as FORMULA36_128_1_, PLANOCONTA1_.CODIGOCONTALALUR as CODIGOC37_128_1_,
       PLANOCONTA1_.REGISTROIMPORTACAOPROCESSO as REGISTR38_128_1_, PLANOCONTA1_.VALORPADRAO as VALORPA39_128_1_,
       PLANOCONTA1_.CODIGOCONTAGRUPOORCAMENTARIO as CODIGOC40_128_1_, PLANOCONTA1_.VARIACAOALERTA as VARIACA41_128_1_,
       PLANOCONTA1_.NUMEROMESESCOMECACAIXA as NUMEROM42_128_1_, PLANOCONTA1_.NUMEROPARCELASGERAL as NUMEROP43_128_1_,
       PLANOCONTA1_.CODIGOCENTROCUSTO as CODIGOC44_128_1_,
       PLANOCONTA1_.CODIGOPLANOCONTASREFERENCIAL as CODIGOP45_128_1_,
       PLANOCONTA1_.CENTROCUSTOOBRIGATORIO as CENTROC46_128_1_, PLANOCONTA1_.LIVROCAIXA as LIVROCAIXA128_1_,
       PLANOCONTA1_.GRUPORELBALANCETE as GRUPORE48_128_1_, PLANOCONTA1_.DETALHACONTABILIDADEBANCO as DETALHA49_128_1_,
       PLANOCONTA1_.NATUREZAFCONT as NATUREZ50_128_1_, PLANOCONTA1_.DEDUZIRDACONTRAPARTIDA as DEDUZIR51_128_1_,
       PLANOCONTA1_.NAORATEARENCCONTASRENEG as NAORATE52_128_1_, PLANOCONTA1_.TIPO2 as TIPO53_128_1_,
       PLANOCONTA1_.PROCESSOCAIXAESCOLAR as PROCESS54_128_1_, PLANOCONTA1_.TEMJUROS as TEMJUROS128_1_,
       PLANOCONTA1_.TEMMULTA as TEMMULTA128_1_, PLANOCONTA1_.TEMRETENCAO as TEMRETE57_128_1_,
       PLANOCONTA1_.TEMDESCONTO as TEMDESC58_128_1_, PLANOCONTA1_.NOMEAUXILIAR as NOMEAUX59_128_1_,
       PLANOCONTA1_.APARECERRECEBIMENTO as APARECE60_128_1_, PLANOCONTA1_.APARECERPAGAMENTO as APARECE61_128_1_,
       PLANOCONTA1_.CUSTEIO as CUSTEIO128_1_, PLANOCONTA1_.CAPITAL as CAPITAL128_1_,
       PLANOCONTA1_.CUSTEIOCAPITAL as CUSTEIO64_128_1_, PLANOCONTA1_.TIPOAPLICACAO as TIPOAPL65_128_1_,
       PLANOCONTA1_.RECEITAS as RECEITAS128_1_, PLANOCONTA1_.RESSARCIMENTOS as RESSARC67_128_1_,
       PLANOCONTA1_.CODIGOSDOCUMENTOS as CODIGOS68_128_1_, PLANOCONTA1_.COLUNAVALOR as COLUNAV69_128_1_,
       PLANOCONTA1_.CODIGOGRUPORESULTADO as CODIGOG70_128_1_, PLANOCONTA1_.CODIGOPRODUTO as CODIGOP71_128_1_,
       PLANOCONTA1_.INDTIPOOPERACAOPISCOFINS as INDTIPO72_128_1_, PLANOCONTA1_.NATUREZABCPISCOFINS as NATUREZ73_128_1_,
       PLANOCONTA1_.INDORIGEMCREDITOPISCOFINS as INDORIG74_128_1_
from TABROTINACONTABILCAIXA ROTINACONT0_
left outer join TABPLANOCONTAS PLANOCONTA1_ on ROTINACONT0_.CODIGOCONTADEBITOPAGAMENTO = PLANOCONTA1_.CODIGO and
      ROTINACONT0_.CODIGOPLANOCONTAS = PLANOCONTA1_.CODIGOPLANOCONTAS
where ROTINACONT0_.CODIGOTIPOCONTABIL = @ P0 and
      ROTINACONT0_.CODIGOPLANOCONTAS = @ P1   

(sendo os parâmetros passados em ComTipoContabil() ​@P0 = tipoContabil @P1 = ​planoContaContaContabil)


TODAS AS COLUNAS mapeadas são projetadas mesmo que façamos acesso à propriedade de apenas uma em código - no caso só preciso da propriedade Tipo em TABPPLANOCONTAS.



A maneira otimizada e que torna a consulta como se fosse a execução de um SQL puro (se fossemos fazer na mão sem usar o repositório) é a seguinte:


var rotinaContabilCaixa = (from rccx in this.RotinasContabeisCaixa.ComTipoContabil(tipoContabil, planoContaContaContabil).Obter() select new { TipoPlanoConta = rccx.ContaContraPartida.Tipo });
​V​
ejam que podemos utilizar tudo como já ocorre na pattern repository sobre filtros - o ComTipoContabil() no caso, sem nenhum impedimento
​.​


select PLANOCONTA2_.TIPO as COL_0_0_
from TABROTINACONTABILCAIXA ROTINACONT0_
left outer join TABPLANOCONTAS PLANOCONTA2_ on ROTINACONT0_.CODIGOCONTADEBITOPAGAMENTO = PLANOCONTA2_.CODIGO and
      ROTINACONT0_.CODIGOPLANOCONTAS = PLANOCONTA2_.CODIGOPLANOCONTAS
where ROTINACONT0_.CODIGOTIPOCONTABIL = @ P0 and
      ROTINACONT0_.CODIGOCONTADEBITOPAGAMENTO = @ P1   

Apenas os campos (e joins também, faça o seu teste para confirmar) que realmente são necessários são projetados, isso gera um ganho enorme de performance pelo custo menor de acesso ao banco de dados e do lado da aplicação menos custo para o bind de "valor de campo-propriedade da coleção" pois o retorno é uma lista de objetos anônimos apenas com as propriedades das colunas projetadas.


​​
​OBS: os aliases colocados pela ORM são automáticos.​


Referências:
  • https://pt.wikipedia.org/wiki/Mapeamento_objeto-relacional
  • http://www.macoratti.net/11/10/net_pr1.htm
  • http://martinfowler.com/eaaCatalog/repository.html

Comentários

Postagens mais visitadas deste blog

Selenium + Firefox = The type initializer for 'System.IO.Compression.ZipStorer' threw an exception

Transmissor sem fio bluetooth Tomate MTB-803 e manual

Problema de rolagem de HTML em iframe no iOS