我正在尝试阅读存储的SQLiteDataReader
对象。理论上,它“应该”起作用,因为对象在引用之前存储在变量中(并且在达到参考线之前不会出现错误),但也许我的想法是错误的。
我正在尝试将我的应用程序保持在一个整齐的分层架构中。因此,每个数据库表都有自己的C#类,它有自己的select,insert,update和delete方法;只有数据层知道如何与数据库等进行通信。
当我尝试创建一个所有数据层类都可以引用的静态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
块之外“存活”?
答案 0 :(得分:3)
这是被处置的连接。数据阅读器只能在连接仍然存在时读取数据。
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
}
}