另外,建议使用 System.Data.Common.DbDataReader,
而不要使用 System.Data.SQLite.SQLiteDataReader。
--------------------------------------------------------------------
SQLiteDataReader继承了DbDataReader
public sealed class SQLiteDataReader : DbDataReader


正是因为 SQLiteDataReader 是从 DbDataReader 中派生出来的,我才建议你使用 DbDataReader 代替 SQLiteDataReader 。
同理,如果可能的话,应该始终只使用 System.Data.Common 命名空间中的类,而不要使用 System.Data.SQLite 命名空间中的类。
先创建一个抽象基类 DbObject:

C# code
 
    
using System;
using System.Data;
using System.Data.Common;

namespace Skyiv.Ben.ProvidentFund.Db
{
public abstract class DbObject
{
public string DbName { get ; private set ; }
protected string dsn { get { return " Data Source= " + DbName; } }
protected DbProviderFactory factory = DbProviderFactories.GetFactory( " System.Data.SQLite " );

protected DbObject( string dbName)
{
DbName
= dbName;
}

protected DbParameter AddParmeter(DbCommand comm, string name, DbType type)
{
var p
= comm.CreateParameter();
p.ParameterName
= name;
p.DbType
= type;
comm.Parameters.Add(p);
return p;
}

}
}



然后,对数据库中的每张表,创建一个从 DbObject 派生的类,如下所示:
C# code
 
    
using System;
using System.IO;
using System.Data;
using System.Data.Common;
using Skyiv.Ben.Common;

namespace Skyiv.Ben.ProvidentFund.Db
{
partial class Passwd : DbObject
{
static readonly int bytes = 160 / 8 ; // SHA1 has 160 bits

public Passwd( string dbName)
:
base (dbName)
{
}

byte [] GetValue( string accno)
{
using (var conn = factory.CreateConnection())
{
conn.ConnectionString
= dsn;
conn.Open();
var comm
= conn.CreateCommand();
comm.CommandText
= " SELECT Value FROM Passwd WHERE Accno=@Accno " ;
AddParmeter(comm,
" Accno " , DbType.String).Value = accno;
var bs
= comm.ExecuteScalar() as byte [];
if (bs == null ) return null ;
if (bs.Length != bytes) throw new Exception( " 密码的密文长度错 " );
return bs;
}
}

void Insert( string accno, byte [] value)
{
using (var conn = factory.CreateConnection())
{
conn.ConnectionString
= dsn;
conn.Open();
var comm
= conn.CreateCommand();
comm.CommandText
= " INSERT INTO Passwd VALUES (@Accno,@Value) " ;
AddParmeter(comm,
" Accno " , DbType.String).Value = accno;
AddParmeter(comm,
" Value " , DbType.Binary).Value = value;
comm.ExecuteNonQuery();
}
}

void Upate( string accno, byte [] value)
{
using (var conn = factory.CreateConnection())
{
conn.ConnectionString
= dsn;
conn.Open();
var comm
= conn.CreateCommand();
comm.CommandText
= " UPDATE Passwd SET Value=@Value WHERE Accno=@Accno " ;
AddParmeter(comm,
" Value " , DbType.Binary).Value = value;
AddParmeter(comm,
" Accno " , DbType.String).Value = accno;
if (comm.ExecuteNonQuery() != 1 ) throw new ArgumentOutOfRangeException( " accno " , " 无此键值 " );
}
}

public int WriteData(BinaryReader br)
{
var recs
= 0 ;
using (var conn = factory.CreateConnection())
{
conn.ConnectionString
= dsn;
conn.Open();
var comm
= conn.CreateCommand();
CreateTable(comm);
comm.CommandText
= " INSERT INTO Passwd VALUES (@Accno,@Value) " ;
var pAccno
= AddParmeter(comm, " Accno " , DbType.String);
var pValue
= AddParmeter(comm, " Value " , DbType.Binary);
comm.Transaction
= conn.BeginTransaction();
try
{
for (; ; recs ++ )
{
pAccno.Value
= br.ReadDecimal();
pValue.Value
= br.ReadBytes(bytes);
if (bytes != (pValue.Value as byte []).Length) throw new InvalidDataException( " 输入文件长度错 " );
comm.ExecuteNonQuery();
}
}
catch (EndOfStreamException) { }
comm.Transaction.Commit();
}
return recs;
}

void CreateTable(DbCommand comm)
{
comm.CommandText
=
" CREATE TABLE Passwd ( " +
" Accno TEXT PRIMARY KEY, " +
" Value BLOB NOT NULL " +
" ) " ;
comm.ExecuteNonQuery();
}
}
}


这样,我们的代码就可以独立了数据库了,随时可以从 SQLite 切换到 MySQL 等数据库。