簡體   English   中英

嘗試從SQLiteDataReader讀取時遇到ObjectDisposedException

[英]Encountering ObjectDisposedException when trying to read from SQLiteDataReader

我正在嘗試通讀存儲的SQLiteDataReader對象。 從理論上講,它“應該”工作,因為對象在被引用之前就存儲在變量中(並且直到到達參考行時才出錯),但是也許我有一個錯誤的主意。

我試圖將我的應用程序保持在整齊的分層體系結構中。 因此,每個數據庫表都具有自己的C#類以及用於選擇,插入,更新和刪除的方法。 只有數據層知道如何與數據庫通信,等等。

較早時,當我嘗試創建一個靜態SQLiteConnection對象時,我遇到了連接問題,所有數據層類都可以引用該對象(以使其保持打開狀態並最大程度地減少開銷(如果有))。 因此,我嘗試using塊來確保每次需要訪問數據庫時都正確處理了連接,並希望這不會導致性能問題。

因此,基本上,這是我的DatabaseConnection類中處理基本查詢執行的方法:

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;
}

這是調用該方法的代碼。 我將以Associate表的對象/記錄為例。

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();
    }
}

這里的想法是,使用rdr對象,我可以直接訪問列名,這樣,如果數據庫發生了變化,我就不必重寫一堆代碼來調整列索引( rdr["id"]rdr["name"]等)

因此,我不明白的是,為什么調用方法中的rdr會出現“對象處置”問題,因為在我引用它之前將其存儲在變量中。 我知道連接位於被調用方法的末尾,但是由於存儲了返回的結果,因此它在技術上是否應該能夠“生存”在using塊之外?

是被配置的連接。 數據讀取器只能在連接仍然存在時讀取數據。

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();
    }
    // *** Connection gone at this stage ***
    return rdr;
}

您的選擇是返回一個DataTable,例如

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

        var dataTable = new DataTable();
        dataTable.Load(rdr);
        return dataTable;
    }
}

否則,您可以在DatabaseConnection類中保持連接處於活動狀態:

class DatabaseConnection : IDisposable
{
    private readonly IDbConnection _conn;

    public DatabaseConnection() 
    {
       _conn = new SQLiteConnection(ConnectionString);
    }

    public void Dispose()
    {
       _conn.Dispose();
    }

    public SQLDataReader ExecuteQuery(string sql) 
    {
        ...
    }
}

// sample usage
using (var conn = new DatabaseConnection())
{
   using (var reader = conn.ExecuteQuery("SELECT ...")
   {
       // do your work in here
   }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM