Array
(
)

Melhor forma de fazer consulta usando linq

Elessandro Poças
   - 05 jun 2015

Olá a todos,
Estou utilizando: Enity Framework Code First + Aplicação Windows Form + SGBD MySQL.
No meu formulário de consulta de fornecedor é possível filtrar por Razão, Fantasia e Cnpj. Bom a consulta está funcionando corretamente, pois tenho 3 métodos na minha camada DAL que conforme código abaixo:
#Código

public List<Fornecedor> FornecedorGetAllRazao(string FornecedorValueRazao, int EmpresaValueId)
        {
            try
            {
                using (var ctx = new Contexto())
                {
                    var consulta = from f in ctx.Fornecedores.ToList()
                                   where (f.Razao.Contains(FornecedorValueRazao) && f.Empresa_Id == EmpresaValueId)
                                   orderby f.Razao
                                   select f;

                    return consulta.ToList();
                }
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }

        public List<Fornecedor> FornecedorGetAllFantasia(string FornecedorValueFantasia, int EmpresaValueId)
        {
            try
            {
                using (var ctx = new Contexto())
                {                    
                    var consulta = from f in ctx.Fornecedores.ToList()
                                   where (f.Fantasia.Contains(FornecedorValueFantasia) && f.Empresa_Id == EmpresaValueId)
                                   orderby f.Razao
                                   select f;

                    return consulta.ToList();
                }
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }

        public List<Fornecedor> FornecedorGetAllCnpj(string FornecedorValueCnpj, int EmpresaValueId)
        {
            try
            {
                using (var ctx = new Contexto())
                {
                    var consulta = from f in ctx.Fornecedores.ToList()
                                   where (f.Cnpj.Contains(FornecedorValueCnpj) && f.Empresa_Id == EmpresaValueId)
                                   orderby f.Razao
                                   select f;

                    return consulta.ToList();
                }
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }

A minha duvida é: Se eu criar um método BuscarTodos() na minha camada DAL conforme o código abaixo:
#Código
 public List<Fornecedor> FornecedorGetAll(int EmpresaValueId)
        {
            try
            {
                using (var ctx = new Contexto())
                {
                    var consulta = from f in ctx.Fornecedores.ToList()
                                   where (f.Empresa_Id == EmpresaValueId)
                                   orderby f.Razao
                                   select f;

                    return consulta.ToList();
                }
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }

E se eu realizar o filtro da minha pesquisa em cima do método BuscarTodos() usando Lambda como no exemplo abaixo:
#Código
private void PesquisarFornecedor()
        {
            List<Fornecedor> lista = fornecedorBLL.FornecedorGetAll(EmpresaValueId);

            if (rbPorRazao.Checked == true)
            {
                lista = lista.Where(f => f.Razao.Contains(txtPesquisar.Text)).ToList();
                if (lista.Count == 0)
                {
                    MessageBox.Show("Nenhum registro encontrado", "SIGPRO - Aviso do Sistema", MessageBoxButtons.OK, MessageBoxIcon.Information);
                    lbNumRegistroRetornados.Text = "0";
                    txtPesquisar.Text = "";
                    txtPesquisar.Focus();
                    dgvFornecedorPesquisar.DataSource = null;
                    return;
                }
                else if (lista.Count != 0)
                {
                    dgvFornecedorPesquisar.DataSource = lista;
                    int qtde = lista.Count();
                    lbNumRegistroRetornados.Text = qtde.ToString();
                }
            }
        }

Com isso poderia ter um ganho de performance e um menor consumo de recursos de rede eu daria na mesma?

Joel Rodrigues
   - 11 jun 2015

Olá, tudo bem?

Bom, isso não vai necessariamente lhe dar ganho de performance. Sobre tráfego de rede, vai ser na verdade maior, pois você estará trazendo todos os registros da tabela, ao invés de apenas os que você deseja.

Tire o ToList() da cláusula from das consultas, pois ela é desnecessária e gera uma lista com todos os registros, impactando no resultado final em termos de desempenho.

Abraço.

Elessandro Poças
   - 12 jun 2015

Olá Joel,

Obrigado pela explicação.

Se eu tirar o ToList() das cláusula from a consulta não retorna nenhum dado. Quando eu usava a verão 4 do Entity Framework a mesma consulta funcionava perfeitamente após a versão 5 tive que usar o ToList() na cláusula from pois sem a mesma a consulta não retorna valores como mostrado na imagem em anexo.

Teste Consulta Linq (Clique na imagem para abrir em uma nova janela)

Agora não sei se estou fazendo algo de errado, se você puder me ajudar, deste já agradeço.

Joel Rodrigues
   - 12 jun 2015

Olha lá em baixo: na variável consulta tem a instrução que está sendo executada, certo? Veja o conteúdo dela pra tentar entender por que não está retornando registro. Se precisar, cole aqui a instrução para analisarmos juntos.
Abraço.

Elessandro Poças
   - 12 jun 2015

Joel, tô mais perdido que cego em tiroteio...

#Código

public List<Cliente> ClienteGetAllNomeRazao(string ClienteValueNomeRazao, int EmpresaValueId)
        {
            try
            {
                using (var ctx = new Contexto())
                {
                    var consulta = from c in ctx.Clientes
                                   where (c.ClienteNome.Contains(ClienteValueNomeRazao) && c.Empresa_Id == EmpresaValueId)
                                   orderby c.ClienteNome
                                   select c;

                    return consulta.ToList();
                }
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }

Joel Rodrigues
   - 12 jun 2015

Ah, eu digo aí nessa imagem mesmo. Veja no canto inferior direito, quando o breakpoint é acionado, a janela "Locals". Uma das linhas é a variável consulta, que no lado direito tem seu valor equivalente em consulta SQL. Veja o conteúdo completo dessa instrução SQL para entender o porquê de não estar retornando registros.

Randrade
   - 12 jun 2015

Alessandro, sobre ganho de desempenho, o Entity Framework peca um pouco. Vale ressaltar que melhorou muito, mas ainda sim é inferior que outros frameworks.

Eu estava tendo alguns problemas quando utilizava o entity. Porém, após algumas pesquisas, eu encontrei o Dapper. Em meus testes, triplicou a velocidade de minhas consultas. Porém, se quer performance mesmo, se cada milésimo importa, você terá que fazer isso via SQL puro mesmo, usando o SqlDataReader.

Segue uma tabela comparativa:
Dapper vs Entity (Clique na imagem para abrir em uma nova janela)

Esta tabela está desatualizada, o entity hoje está na faixa de 180ms.

Elessandro Poças
   - 12 jun 2015

Joel,

Refiz a consulta da seguinte forma:

#Código

public List<Cliente> ClienteGetAllNomeRazao(string ClienteValueNomeRazao, int EmpresaValueId)
        {
            try
            {
                using (var ctx = new Contexto())
                {
                    var consulta = from c in ctx.Clientes.AsEnumerable().Where(c => c.ClienteNome.Contains(ClienteValueNomeRazao) && c.Empresa_Id == EmpresaValueId)                                   
                                   orderby c.ClienteNome
                                   select c;

                    return consulta.ToList();
                }
            }
            catch (Exception ex)
            {                
                throw new Exception(ex.Message);
            }
        }


Desta forma o from só buscou os dados que eu precisava, conforme imagem abaixo.
Clique na imagem para abrir em uma nova janela