Error: Undefined object reference for an object instance, how to resolve?

Asked

Viewed 4,252 times

4

I have the method ChamadaEfetuada(MAluno) : bool checking whether the call was made to a particular student, this method is used in another method ChamadaEfetuada() : bool that instead of checking if the call was made to a single student, he checks all students at once, and he only returns true if the call was made to all students.

But I’m getting an error in my method ChamadaEfetuada() : bool with the following message:

Undefined object reference for an object instance.

Error occurs on this line:

alunos[i].IdAluno = Convert.ToInt32(registro["id_aluno"]);

Compiler says the problem is in my array alunos.

Complete code of the method ChamadaEfetuada(MAluno) : bool:

public bool ChamadaEfetuada(MAluno aluno) 
        {
            string query = "SELECT id_aluno FROM Lista_presenca WHERE id_aluno = " + aluno.IdAluno + " AND data = '" + this.Hoje() + "'";

            DadosConexao dados_conexao = new DadosConexao();

            SQLiteConnection conexao = this.conexao.Conexao;
            conexao.Open();

            SQLiteCommand command = conexao.CreateCommand();
            command.CommandText = query;            

            SQLiteDataReader registro = command.ExecuteReader();

            bool existe_registro = registro.HasRows;

            conexao.Close();

            return existe_registro;            
        }

Complete code of the method ChamadaEfetuada() : bool:

public bool ChamadaEfetuada() 
        {
            string query = "SELECT id_aluno FROM Alunos";

            int total_alunos = 0, alunos_chamada_efetuada = 0;

            DadosConexao dados_conexao = new DadosConexao();

            SQLiteConnection conexao = this.conexao.Conexao;
            conexao.Open();

            SQLiteCommand command = conexao.CreateCommand();
            command.CommandText = query;

            SQLiteDataReader registro = command.ExecuteReader(); //Obtem os IDs de todos os alunos

            MAluno[] alunos = new MAluno[registro.FieldCount];

            total_alunos = registro.FieldCount;

            int i = 0;            

            while (registro.Read())
            {                
                alunos[i].IdAluno = Convert.ToInt32(registro["id_aluno"]); //Popula o atributo IdAluno do objeto alunos com os IDs obtidos pela query. Porem aqui acontece o erro.
                i++;                
            }

            conexao.Close();

            for (i = 0; i < registro.FieldCount; i++)
            {
                if (this.ChamadaEfetuada(alunos[i])) 
                {
                    alunos_chamada_efetuada++;
                }
            }

            if (alunos_chamada_efetuada == total_alunos)
                return true;
            else
                return false;
        }

The two methods above are part of my class BLLListaPresenca.

2 answers

4


I don’t know if I’ll help you because these error messages in Portuguese get in the way and information is missing that might indicate why the error.

I’ll guess you don’t want the FieldCount after all it doesn’t matter how many columns there are. It matters how many rows there are, and this information is not available and then you can’t use one array (in fact almost always that one uses a array, is making a mistake). You would have to use a list to add the available lines to it. You can even use the array, but the gambiarra is so big that I won’t even describe.

To tell you the truth I have my doubts if I create this array or list is really necessary. It is even in this code but it is with several problems.

The code is very confusing, uses wrong techniques, unnecessary codes, methods do more than they should, are repetitive, unreliable, insecure, rather inefficient and in this way, one method calling the other should be the last thing to do. It would need a complete restructuring.

  • You are sure the number of columns is not what I need, I want to get the number of rows that the query returns me. But I’m having a hard time implementing this business rule, which is to see if the call of the day has been made. You have some hint of how I can restructure this code?

  • 1

    Start by eliminating all variables that are used zero times, then the ones that are used only once (it is rare for a variable that is used once to be useful, none in this case). Give the class a read SqlDataReader. See how to use it, what methods and existing properties they are. Start using using, Use the parameters of SQLiteCommand . Switch to `List<T>. There’s more. This is just the beginning.

  • I will take a look here about the parameters of Sqlitecommand and also the class Sqldatareader. The List<T> what would it be, an object list like array? I want to go deeper into it.

  • Ask specific questions with every question you have.

3

Following Maniero’s recommendations I made the changes in my method ChamadaEfetuada() : bool and removed the method ChamadaEfetuada(MAluno) : bool. Replaces the array MAlunos[] alunos by a list List<T> and made the implementation of the rule that is check if the call has already been made to all students in my method, I have also correctly implemented the parameters of my SQLiteCommand to perform the research.

Below follows the method ChamadaEfetuada() : bool (restructured) which is the solution of the above problem:

public bool ChamadaEfetuada() 
{   
    /*Listas*/
    var alunos = new List<MAluno>();
    var alunos_chamada = new List<MAluno>();

    /*Prepara a conexão*/            
    SQLiteConnection conexao = this.conexao.Conexao;
    conexao.Open();

    using (SQLiteCommand command = conexao.CreateCommand()) 
    {                
        command.CommandText = "SELECT id_aluno FROM Alunos";

        SQLiteDataReader registro = command.ExecuteReader();

        if (registro.HasRows)
        {
            while (registro.Read())
            {
                alunos.Add(new MAluno
                {
                    IdAluno = Convert.ToInt32(registro.GetValue(0))
                });
            }
        }
        else
        {
            conexao.Close();
            return false;
        }

        conexao.Close();
    }

    conexao.Open();

    using (SQLiteCommand command = conexao.CreateCommand()) 
    {                
        foreach (var aluno in alunos) 
        {                    
            command.Parameters.Add("id_aluno", DbType.Int32).Value = aluno.IdAluno;
            command.Parameters.Add("data", DbType.String).Value = this.hoje;
            command.CommandText = "SELECT id_aluno FROM Lista_Presenca WHERE id_aluno = ? AND data = ?";

            SQLiteDataReader registro = command.ExecuteReader();

            if (registro.HasRows)
            {
                registro.Read();

                alunos_chamada.Add(new MAluno
                {
                    IdAluno = Convert.ToInt32(registro.GetValue(0))
                });                        
            }
            else 
            {
                conexao.Close();
                return false;
            }

            registro.Close();            
        }

        conexao.Close();
    }

    return (alunos.Count == alunos_chamada.Count);
}
  • 1

    It can still be improved, but it’s something else. Much better.

  • If you have more suggestions can tell me that I try to implement here :)

Browser other questions tagged

You are not signed in. Login or sign up in order to post.