lundi 31 août 2015

Encountering ObjectDisposedException when trying to read from SQLiteDataReader

I am trying to read through a stored SQLiteDataReader object. In theory, it "should" work because the object is stored in a variable before it is referenced (and doesn't hit an error until the reference line is reached), but maybe I have the wrong idea.

I'm trying to keep my application in a neatly layered architecture. So, each database table having its own C# class with its own methods for select, insert, update, and delete; only the data layer knows how to communicate with the database, etc.

I was running into connection issues earlier when I tried to make one static SQLiteConnection object that all the data layer classes could reference (so as to keep it open and minimize overhead, if any). So I'm trying to go with the using block to make sure the connection is properly disposed each time I need to access the database, and hoping that this won't cause performance issues.

So basically, here is the method in my DatabaseConnection class that handles basic query execution:

public SQLiteDataReader ExecuteQuery(string sql)
{
    SQLiteDataReader rdr = null;
    using(SQLiteConnection conn = new SQLiteConnection(ConnectionString))
    {
        conn.Open();
        SQLiteCommand cmd = conn.CreateCommand();
        cmd.CommandText = sql;
        rdr = cmd.ExecuteReader();
    }
    return rdr;
}

And here is the code that calls that method. I'll use an object/record of the Associate table as an example.

public class Associate
{
    public int RowId { get; private set; }
    public int Id { get; set; }
    public string Name { get; set; }

    private string password;
    public string Password
    {
        get
        {
            return password;
        }
        set
        {
            password = Hash(value); // external password hashing method
        }
    }

    public Associate() { } // default constructor with default values

    public Associate(int id)
    {
        this.Id = id;
        Select();
    }

    // select, insert, update, delete methods
    private void Select() { ... }

    // these are non-queries and return true/false based on success
    public bool Insert() { ... }
    public bool Update() { ... }
    public bool Delete() { ... }

    /* Method that causes the error */
    public static Associate[] GetAll()
    {
        DatabaseConnection con = new DatabaseConnection();
        SQLiteDataReader rdr = con.ExecuteQuery("SELECT id FROM Associate");

        List<Associate> list = new List<Associate>();

        if (rdr != null)
        {
            while (rdr.Read()) /* this line throws the exception */
            {
                int next = rdr.GetInt32(0);
                list.Add(new Associate(next));
            }
        }

        return list.ToArray();
    }
}

The idea here is that using the rdr object, I can access the column names directly so that if the database ever changes, I won't have to rewrite a bunch of code to adjust for the column indices (rdr["id"], rdr["name"], etc.)

So what I don't understand is why rdr in the calling method is having "object disposed" issues because it's stored in a variable before I reference it. I know the connection is disposed at the end of the called method, but since the returned result is stored, shouldn't it technically be able to "survive" outside the using block?

Aucun commentaire:

Enregistrer un commentaire