Solucionado (ver solução)
Solucionado
(ver solução)
7
respostas

Dificuldades em realizar consulta na tabela pela camada controller.

Estou fazendo um sistema simples de consulta contato, com base no curso, mas estou com dificuldades em realizar consulta na tabela pela camada controller.

public async Task<IActionResult> Index(string busca)
        {
            var contato = from c in contatoRepository.GetContatos() select c;

            if (!String.IsNullOrEmpty(busca))
            {
                contato = contato.Where(s => s.Nome.Contains(busca));
            }

            return View(await contato.ToListAsync());
        }

contatoRepository.GetContatos() é uma referencia ao meu contexto.

Gravidade Código Descrição Projeto Arquivo Linha Estado de Supressão

Erro CS1935 Não foi possível encontrar uma implementação do 
padrão de consulta para o tipo de origem 
"IList<AgendaModel.Contato>". "Select" não encontrado. Está 
faltando uma referência a "System.Core.dll" ou uma diretiva using 
para "System.Linq"? MizuAgenda_Core 
C:\Users\thiagogriao\source\repos\MizuAgenda_Core\MizuAgenda
_Core\Controllers\AgendaController.cs 26 Ativo

Se eu adiciono o System.Linq

o erro muda para:

Gravidade Código Descrição Projeto Arquivo Linha Estado de 
Supressão
Erro CS1061 'IEnumerable<AgendaModel.Contato>' não contém 
uma definição para 'ToListAsync' e não foi possível encontrar 
nenhum método de extensão 'ToListAsync' acessível que aceite um 
primeiro argumento do tipo 'IEnumerable<AgendaModel.Contato>' 
(há uma diretiva de uso ou referência de assembly ausente?) 
MizuAgenda_Core C:\Users\thiagogriao\source\repos\MizuAgenda_Core\MizuAgenda_Core
\Controllers\AgendaController.cs 33 Ativo
7 respostas

Oi Thiago, tudo bem?

O método ToListAsync() é a versão assíncrona do método ToList(). Mas como a interface IEnumerable não suporta o método ToListAsync, você está recebendo esse erro.

Você pode postar aqui o código da classe ContatoRepository para darmos uma olhada? Acredito que você esteja chamando o método ToList() nos contatos do método GetContatos() do seu repositório antes de retornar o resultado do método, e esse pode ser a causa do problema.

Bom dia!

Tudo ótimo e com você Marcelo?

Pelo que observei aqui estou usando o método ToList() .

Segue código da classe ContatoRepository :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using MizuAgenda_Core.Models;
using static MizuAgenda_Core.Models.AgendaModel;

namespace MizuAgenda_Core.Repositories
{
    public class ContatoRepository : BaseRepository<Contato>, IContatoRepository
    {
        public ContatoRepository(ApplicationContext contexto) : base(contexto)
        {
        }

        public IList<Contato> GetContatos()
        {
            return dbSet.ToList();
        }

        public void SaveContatos(List<DadosContatos> dadoscontatos)
        {
            foreach (var dado in dadoscontatos)
            {
                if (!dbSet.Where(d => d.Nome == dado.name).Any())
                {
                    dbSet.Add(new Contato(dado.name, dado.office, dado.department, dado.telephonenumber, dado.fax, dado.mail));
                }
            }
            contexto.SaveChanges();
        }
    }
    public class DadosContatos
    {
        public string name { get; set; }
        public string office { get; set; }
        public string department { get; set; }
        public string telephonenumber { get; set; }
        public string fax { get; set; }
        public string mail { get; set; }
    }
}

Oi Thiago, tudo joia!

Agora entendi. O problema está neste método:

        public IList<Contato> GetContatos()
        {
            return dbSet.ToList();
        }

O que aconteceu? O método ToList() é síncrono, isto é, ele vai esperar o resultado da lista que foi carregada do banco de dados para a memória, e a partir daí, todas as consultas vão trabalhar com dados diretamente da memória.

Acontece que você não precisa desse ToList() nesse momento. Você pode simplesmente retornar os contatos como um IQueryable,

        public IQueryable<Contato> GetContatos()
        {
            return dbSet;
        }

Isso é possível porque a classe DbSet<T> implementa a interface IQueryable<T>.

De qualquer forma, o método ToListAsync() que você está tentando usar não se aplica aqui. Você pode retornar para a view simplesmente o contato, desta forma: return View(contato);:

public IActionResult Index(string busca)
{
    var contato = from c in contatoRepository.GetContatos() select c;

    if (!string.IsNullOrEmpty(busca))
    {
        contato = contato.Where(s => s.Nome.Contains(busca));
    }

    return View(contato);
}

Mas note que aqui você pode melhorar o código: note que, ao fazer pesquisa por nome dentro do Controler, você está colocando uma lógica de banco de dados dentro da lógica de apresentação. isso não é bom. Mova essa lógica para dentro do repositório:

No repositório:

        public IQueryable<Contato> GetContatos(string busca)
        {
            if (!string.IsNullOrEmpty(busca))
            {
                return dbSet.Where(s => s.Nome.Contains(busca));
            }

            return dbSet;
        }

E no controller ficaria assim:

        public IActionResult Index(string busca)
        {
            var contato = from c in contatoRepository.GetContatos() select c;
            return View(contato);
        }

Mas você também deveria melhorar o código desse controller. Note que a query LINQ from c in contatoRepository.GetContatos() select c é desnecessária, pois você não está modificando os dados de retorno com a cláusula SELECT, nem usando filtro com a cláusula WHERE nem fazendo ordenação nem agrupamento. Então você pode eliminar essa query LINQ totalmente:

        public IActionResult Index(string busca)
        {
            return View(contatoRepository.GetContatos(busca));
        }

Marcelo, desculpe a demora pelo retorno.

Agora está retornando o Erro CS0535 "ContatoRepository" não implementa membro de interface "IContatoRepository.GetContatos()"

Pelo que notei ele não esta aceitando o " string busca" dentro da lógica do repositório:

public IQueryable<Contato> GetContatos(string busca)
        {
            if (!string.IsNullOrEmpty(busca))
            {
                return dbSet.Where(s => s.Nome.Contains(busca));
            }

            return dbSet;
        }

E sobre o uso da query LINQ, eu quero modificar os retornos com o SELECT e usar filtros com o WHERE, poderia me indicar como consigo usar essas cláusulas, estou criando uma lista de contatos com base das informações do AD, e isso seria muito interessante para o desenvolvimento.

Oi Thiago

Esqueci de mencionar que você precisa alterar esta linha na inteface IContatoRepository:

IQueryable<Contato> GetContatos(string busca)

A cláusula where você já está usando no método GetContatos(), certo?

public IQueryable<Contato> GetContatos(string busca)
{
    if (!string.IsNullOrEmpty(busca))
    {
        return dbSet.Where(s => s.Nome.Contains(busca));
    }

    return dbSet;
}

O que mais você gostaria de filtrar? E quanto ao uso do select, ele só fará sentido se você quiser modificar os valores retornados, em vez de manter o resultado como uma lista de Contato. O que você quer exatamente que o método GetContatos() retorne?

Obrigado!

Alterei aqui como sugerido, funcionou perfeitamente!

Eu queria filtrar todos os campos independente do que fosse escrito, criei uma aplicativo em C# com Windows Forms que faz esse processo e estou buscando passar para uma aplicação Web. No aplicativo usei os recurso do Sql para realizar a pesquisa.

Código C#:

private void Txt_consulta_TextChanged(object sender, EventArgs e)
        {            
            SqlConnection cnx = new SqlConnection(@"Data Source=SRV-TESTE;Initial Catalog=AGENDA;User ID=agenda;Password=***********");

            string sqlString = "SELECT nome as 'NOME', office as 'UNIDADE', department as 'DEPARTAMENTO', telephonenumber as 'TELEFONE', fax as 'RAMAL', mail as 'E-MAIL' FROM CONTATO WHERE office <> '' AND (nome LIKE '%" + Txt_consulta.Text + "%' OR office LIKE '%" + Txt_consulta.Text + "%' OR department LIKE '%" + Txt_consulta.Text + "%' OR telephonenumber LIKE '%" + Txt_consulta.Text + "%' OR fax LIKE '%" + Txt_consulta.Text + "%' OR mail LIKE '%" + Txt_consulta.Text + "%') ORDER BY office, nome, department";

            SqlCommand comand = new SqlCommand(sqlString, cnx);

            try
            {
                SqlDataAdapter objAp = new SqlDataAdapter(comand);

                DataTable dt = new DataTable();

                objAp.Fill(dt);

                Dgt_contatos.DataSource = dt;

            }
            catch (Exception ex)
            {
                throw ex;
            }
            finally
            {
                cnx.Close();
            }            
        }

Realizava a busca em todos os campo e retornava no DataGridView ordenando os campos.

solução!

Bom dia Marcelo!

Consegui resolver aqui, adicionei a query LINQ novamente na AgendaController e adicionei operadores OR para o ContatoPepository. Ficou assim:

Repositório:

public IQueryable<Contato> GetContatos(string busca)
        {
            if (!string.IsNullOrEmpty(busca))
            {
                return dbSet.Where(s => s.Nome.Contains(busca) 
                || s.Unidade.Contains(busca) 
                || s.Departamento.Contains(busca) 
                || s.Telefone.Contains(busca) 
                || s.Telefone.Contains(busca)
                || s.Email.Contains(busca));
            }

            return dbSet;
        }

Controller:

  public IActionResult Index(string busca)
        {
            var contato = from c in contatoRepository.GetContatos(busca)
                          where c.Unidade != "" & c.Departamento != "TI"
                          orderby c.Nome ascending
                          select c;
            return View(contato);
        }

Obrigado pelo apoio!