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

Loop foreach para listas de Select pelo MySql

Olá, gostaria de saber se alguém pode me ajudar.

Estou tentando realizar um select do mysql de forma genérica, mas não consigo jogar na tela os dados de forma correta.

Resultado esperado: Id: id1 Nome: nome1 Email: email1 Id: id2 Nome: nome2 Email: email2 E continua ate que não sobre mais linhas lidas pelo MySqlDataReader.

Resultado obtido: Id: id1 Nome: id1 Email: id1 Id: nome1 Nome: nome1 Email: nome1

Sei que isso ocorre, pois o loop está sendo feito a partir da mesma linha e só prossegue para a próxima quando todas as colunas tenham sido mostradas, mas não sei como prosseguir daqui.

Segue código: Classe model Usuários:

public class Usuarios : Interfaces.ITabela
    {
        public int IdUsuarios { get; set; }
        public string Nome { get; set; }
        public string Email { get; set; }

        private List<string> Colunas { get; set; }
        private List<string> Parametros { get; set; }


        public Usuarios()
        {
            Parametros = new List<string>();
            Parametros.Add("''");
            Parametros.Add("@Nome");
            Parametros.Add("@Email");

            Colunas = new List<string>();
            Colunas.Add("IdUsuarios");
            Colunas.Add("Nome");
            Colunas.Add("Email");
        }

        public List<string> GetParametros()
        {
            return Parametros;
        }

        public List<string> GetColunas()
        {
            return Colunas;
        }
    }

Classe de controle para ler os dados do banco de dados:

public interface ILerDados
    {
        List<string> Ler();
    }

    internal class LerDados : ILerDados
    {
        private readonly MySql.Data.MySqlClient.MySqlConnection conexao;
        private readonly MySql.Data.MySqlClient.MySqlCommand comando;
        private MySql.Data.MySqlClient.MySqlDataReader leitor;
        private List<string> colunas;

        public LerDados(List<string> colunas, string stringConexao, string query)
        {
            this.conexao = new MySql.Data.MySqlClient.MySqlConnection(stringConexao);
            this.comando = new MySql.Data.MySqlClient.MySqlCommand(query, conexao);
            this.colunas = colunas;
        }

        public List<string> Ler()
        {
            List<string> resultado = new List<string>();

            conexao.Open();

            try
            {
                using (comando)
                {
                    leitor = comando.ExecuteReader();

                    while (leitor.Read())
                    {
                        foreach (string coluna in colunas)
                        {
                            resultado.Add(Convert.ToString(leitor[$"{coluna}"].ToString()));
                        }
                    }

                }
                return resultado;
            }
            catch (MySql.Data.MySqlClient.MySqlException e)
            {
                Console.WriteLine("Erro no comando Ler.");
                throw e;
            }
            catch (NullReferenceException e)
            {
                throw e;
            }
            finally
            {
                conexao.Close();
            }
        }
    }

AQUI O PROBLEMA (foreach loop): Dao controller que pega o método Ler() e concatena com as colunas que existem na classe model Usuarios para formar uma tabela:

public IEnumerable<string> ComandoSelect()
        {
            query = $"SELECT * FROM {nomeTabela}";

            Leitor = new LerDados(tabela.GetColunas(), stringConexao, query);

            var resultado = new List<string>();
            try
            {
              foreach (string linha in Leitor.Ler())
                {
                    foreach (var coluna in tabela.GetColunas())
                    {
                        resultado.Add($"{coluna}: {linha}");
                    }
                }
                return resultado;
            }
            catch (MySql.Data.MySqlClient.MySqlException e)
            {
                throw e;
            }
        }

Segue Program onde mostro em tela cada um dos itens na lista de retorno resultado do método ComandoSelect():

static void Main(string[] args)
        {
            var dadosTabela = new List<string>();

            try
            {
                Dao.Dao usuarioDao = new Dao.Dao("usuarios");

                Console.WriteLine("Tabela Usuarios");
                foreach (var item in usuarioDao.ComandoSelect())
                {
                    Console.WriteLine(item);
                }

            }
            catch (Exception e)
            {
                Console.WriteLine(e);
            }
            finally
            {
                Console.ReadKey();
            }

Agradeço quer puder ajudar!

8 respostas

Thiago,

Estou tentando recriar o código aqui em casa, mas fiquei com algumas dúvidas:

1 - O que tem dentro de "ITabela"?

2 - O que é um "Dao.Dao"?

3 - Você está usando o "MySql.Data.Entityframework"?

[]'s,

Fabio I.

Boa tarde Fabio.

Agradeço a ajuda e peço desculpas pela falta de informações, sou muito novo nisso tudo.

Vamos lá:

1 - ITabela é uma interface para chamar as colunas e os parâmetros das models (tabelas) que existem no código. Chamo ela a partir de uma Factory (TabelaFactory). Tem apenas dois métodos:

    public interface ITabela
    {
        List<string> GetParametros();
        List<string> GetColunas();
    }

2 - Como estou evitando usar o tal do "Ctrl + ." para adicionar referências (li em alguns lugares que isso é uma má pratica de programação) eu estou chamando direito por Dao(diretório).Dao(classe).

3- Não estou. Pq, acha que é melhor? Nunca usei. Uso apenas o MySql.Data.

Meu objetivo é aprender a fazer na marra o que o Dapper (por exemplo) faz. Por isso não estou usando nada que não seja o básico.

Subi esse código em um repositório no GitHub pra que tu possa rodá-lo. O script do banco de dados está dentro da pasta "Arquivos Adicionais" do repositório (estou usando apenas a table usuarios para estes teste iniciais).

Segue link: https://github.com/PachukanisProgramador/NovoReclameAcesso.git

Agradeço demais pela ajuda!

Thiago,

1 - Beleza preenchi aqui;

2 - Ué? Não acho uma "má prática de programação", mas se você quer DECORAR, isso eu concordo, pois muitos testes de empresa são na caneta e papel;

3 - Não. Era só para saber;

DAPPER? Não conhecia. Parece bacana, depois vou olhar...

================================================

C# - Dapper básico (revisitado) via Console

https://www.macoratti.net/19/09/cshp_dapb1.htm

================================================

Beleza! Olhei código do GitHub que você passou... o meu resultado deu nisto:

ERRO

Deixa ver se eu entendi ... o erro é esta duplicidade? Acredito que sim... okay, vou olhar melhor o código.

Detalhe: Eu que preenchi estes dados dentro do meu MySql.

[]'s,

Fabio I.

Thiago,

Okay... fiz a seguinte modificação, retirei o duplo "foreach" e coloquei um "for" :

public IEnumerable<string> ComandoSelect()
{
    int y = 0;

    query = $"SELECT * FROM {nomeTabela}";

    Leitor = new LerDados(tabela.GetColunas(), stringConexao, query);

    var resultado = new List<string>();
    List<string> resultadoLeitor = Leitor.Ler();
    List<string> resultadoColunas = tabela.GetColunas();

    try
    {
        //foreach (string linha in resultadoLeitor)
        //{
        //    foreach (var coluna in tabela.GetColunas())
        //    {
        //        resultado.Add($"{coluna}: {linha}");
        //    }
        //}

        resultado.Add("------------------------");

        for (int x = 0; x < resultadoLeitor.Count; x++)
        {
            if (y >= resultadoColunas.Count)
            {
                y = 0;
                resultado.Add("------------------------");
            }

            resultado.Add($"{resultadoColunas[y]}: {resultadoLeitor[x]}");
            y++;
        }

        resultado.Add("------------------------");

        return resultado;
    }
    catch (MySql.Data.MySqlClient.MySqlException e)
    {
        throw e;
    }
}

Veja se está certo.

[]'s,

Fabio I.

Fala Fabio.

Sobre a questão de má prática de programação, como sou novo estou indo no que me dizem, mas se você diz que não é então tudo. Mas, realmente, é uma boa forma para decorar. Obrigado pela dica.

Mais tarde darei uma olhada neste artigo do Marcoratti. Ele é muito bom.

Sim, o problema do meu código é esta duplicidade. Ele está lendo um campo de uma linha do banco de dados apenas e colocando em cada uma das colunas. Após o loop das colunas ter-se completado ele torna a mostrar o segundo campo da mesma colunas e assim por diante.

Testei o seu código e o compilador retornou um ArgumentOutOfRangeException.

Já tinha tentado com esse loop for antes e nada.

Acontece que quando usamos o resultadoLeitor.Count o loop vai repetir enquanto houver campos para ler através do MySqlDataReader (limite indefinido pela abstração do método ComandoSelect()), mas o método tabela.GetColunas() só vai até 3 (que é, no caso de Usuários, o campo "Email"). Por isso a exceção lançada.

Deve haver um modo de zerar o loop de tabela.GetColunas() enquanto permanece na mesma contagem do Leitor.Ler(), não?

Tenho em mente em usar esse loop com resultadoLeitor.Count, mas agora estou sem tempo, pois estou de saída aqui de minha casa e só poderei mexer nisso amanhã.

Se conseguir algum modo para fazer isso funcionar agradeceria imensamente.

Independentemente de qualquer coisa agradeço muito mesmo sua ajuda Fabio!

Se cuida!

solução!

Thiago,

Consegui agora! Esqueci que precisava restartar a variável! MOTIVO: Eu estava testando com somente um registro. Por favor, veja se está certo agora:

public IEnumerable<string> ComandoSelect()
{
    int y = 0;

    query = $"SELECT * FROM {nomeTabela}";

    Leitor = new LerDados(tabela.GetColunas(), stringConexao, query);

    var resultado = new List<string>();
    List<string> resultadoLeitor = Leitor.Ler();
    List<string> resultadoColunas = tabela.GetColunas();

    try
    {
        resultado.Add("------------------------");

        for (int x = 0; x < resultadoLeitor.Count; x++)
        {
            if (y >= resultadoColunas.Count)
            {
                y = 0;
                resultado.Add("------------------------");
            }

            resultado.Add($"{resultadoColunas[y]}: {resultadoLeitor[x]}");
            y++;
        }

        resultado.Add("------------------------");

        return resultado;
    }
    catch (MySql.Data.MySqlClient.MySqlException e)
    {
        throw e;
    }
}

Em outras palavras... assim que o número de colunas for ultrapassado, é preciso reiniciar a contagem a partir do zero exatamente como você disse.

Desculpe a mancada.

[]'s,

Fabio I.

Fala Fabio.

É exatamente isso!

Só faltava uma outra variável para representar o loop.

To mexendo tanto com esses foreach e lists que fico ate confuso as vezes.

Coloquei abaixo de uma forma mais crua pra quem se interessar.

public IEnumerable<string> ComandoSelect()
        {

            query = $"SELECT * FROM {nomeTabela}";

            Leitor = new LerDados(tabela.GetColunas(), stringConexao, query);

            int loopColunas = 0;
            var resultado = new List<string>();

            try
            {
                foreach (var campo in Leitor.Ler())
                {
                    if (loopColunas >= tabela.GetColunas().Count)
                    {
                        loopColunas -= tabela.GetColunas().Count;
                    }

                    resultado.Add($"{tabela.GetColunas()[loopColunas]}: {campo}");
                    loopColunas++;
                }
                return resultado;
            }
            catch (MySql.Data.MySqlClient.MySqlException e)
            {
                throw e;
            }
        }

Resultado:

Insira aqui a descrição dessa imagem para ajudar na acessibilidade

E fica tranquilo. Ajudou demais.

Muito obrigado Fabio!

Bom fds e se cuida!

Perfeito Thiago!

Obrigado por marcar minha solução. Qualquer problema chama aqui.

Você também pode colocar sua dúvida no:

ou outro fórum bacana. Até mais!

[]'s,

Fabio I.