我正在尝试为ado.net编写一个包装类,问题是我得到以下错误,我不知道如何解决它。
我已经阅读了很多关于此问题的其他问题,但没有一个使用包装类,因此没有帮助。
任何人都可以指出我正确的方向或提供相同问题的链接,以便我可以阅读如何解决它。或者我完全以错误的方式去做。
public List<LoginDetails> Authenticate(string id)
{
const string spName = "dbo.MemberLogin";
List<SqlParameter> parameters = new List<SqlParameter> { new SqlParameter("@Username", id) };
var rdr = _iAdoCommandWrapper.ExecuteDataReaderAsync(DbConnectionAbstractClass.ConnectionString, CommandType.StoredProcedure, spName, parameters.ToArray());
var data = new List<LoginDetails>();
if (rdr.HasRows)
{
while (rdr.Read())
{
data.Add(new LoginDetails
{
UserName = (string)rdr["MemberUsername"],
Password = (string)rdr["MemberPassword"],
MemberId = (string)rdr["MemberID"],
Role = (string)rdr["MemberRole"]
});
}
//-------
rdr.NextResult();
while (rdr.Read())
{
data.Add(new LoginDetails
{
RolesForMember = (string)(rdr["MembersRoles"])
});
}
//----------
}
return data.ToList();// rowsAffected.Result;
}
包装
public SqlDataReader ExecuteDataReaderAsync(string connectionString, CommandType cmdType, string spName, params SqlParameter[] cmdParameters)
{
//TODO make async once fixed problem
using (var conn = new SqlConnection(connectionString))
{
using (var cmd = new SqlCommand(spName, conn))
{
cmd.CommandType = cmdType;
cmd.Parameters.AddRange(cmdParameters);
conn.Open();
return cmd.ExecuteReader(CommandBehavior.Default);
}
}
}
答案 0 :(得分:1)
DataReader
实际上只针对这种情况采取行为CommandBehavior.CloseConnection
。
public SqlDataReader ExecuteDataReaderAsync(string connectionString, CommandType cmdType, string spName, params SqlParameter[] cmdParameters)
{
// These two are intentionally are not in a using statement, but it is ok, closing
// the reader cleans up the resources.
var conn = new SqlConnection(connectionString))
var cmd = new SqlCommand(spName, conn))
cmd.CommandType = cmdType;
cmd.Parameters.AddRange(cmdParameters);
conn.Open();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
当您处置DataReader
时,它会关闭SqlConnection
,这就是处理连接的行为(加上Disposed
事件)。
唯一处理SqlCommand
的做法是释放对内部变量_cachedMetaData
的引用,以允许它更早地获得GC并在{{{{}}上调用基础Dispose(bool)
1}}它唯一能做的就是引发Component
事件。
只要您没有使用连接的Disposed
事件或命令或连接,此解决方案就适合您。
如果你真的必须&#34;正确&#34;处置这两个因为你依赖于事件,使用类似于I ran in to a similar situation处理Disposed
时所做的伎俩。制作一个包装器,在读取器被丢弃时处理你的连接和命令。
CryptoStream
与
一起使用sealed class CleaningDataReader : IDataReader
{
private readonly IDataReader _reader;
private readonly IDisposable[] _itemsToDispose;
public CleaningDataReader(IDataReader reader, params IDisposable[] itemsToDispose)
{
if(reader == null)
throw new ArgumentNullException("reader");
_reader = reader;
_itemsToDispose = itemsToDispose;
}
public void Dispose()
{
_reader.Dispose();
if (_itemsToDispose != null)
{
foreach (var item in _itemsToDispose)
{
if(item != null)
item.Dispose();
}
}
}
public void Close()
{
_reader.Close();
}
public int Depth
{
get { return _reader.Depth; }
}
public int FieldCount
{
get { return _reader.FieldCount; }
}
public bool GetBoolean(int i)
{
return _reader.GetBoolean(i);
}
public byte GetByte(int i)
{
return _reader.GetByte(i);
}
public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
{
return _reader.GetBytes(i, fieldOffset, buffer, bufferoffset, length);
}
public char GetChar(int i)
{
return _reader.GetChar(i);
}
public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
{
return _reader.GetChars(i, fieldoffset, buffer, bufferoffset, length);
}
public IDataReader GetData(int i)
{
return _reader.GetData(i);
}
public string GetDataTypeName(int i)
{
return _reader.GetDataTypeName(i);
}
public DateTime GetDateTime(int i)
{
return _reader.GetDateTime(i);
}
public decimal GetDecimal(int i)
{
return _reader.GetDecimal(i);
}
public double GetDouble(int i)
{
return _reader.GetDouble(i);
}
public Type GetFieldType(int i)
{
return _reader.GetFieldType(i);
}
public float GetFloat(int i)
{
return _reader.GetFloat(i);
}
public Guid GetGuid(int i)
{
return _reader.GetGuid(i);
}
public short GetInt16(int i)
{
return _reader.GetInt16(i);
}
public int GetInt32(int i)
{
return _reader.GetInt32(i);
}
public long GetInt64(int i)
{
return _reader.GetInt64(i);
}
public string GetName(int i)
{
return _reader.GetName(i);
}
public int GetOrdinal(string name)
{
return _reader.GetOrdinal(name);
}
public DataTable GetSchemaTable()
{
return _reader.GetSchemaTable();
}
public string GetString(int i)
{
return _reader.GetString(i);
}
public object GetValue(int i)
{
return _reader.GetValue(i);
}
public int GetValues(object[] values)
{
return _reader.GetValues(values);
}
public bool IsClosed
{
get { return _reader.IsClosed; }
}
public bool IsDBNull(int i)
{
return _reader.IsDBNull(i);
}
public object this[int i]
{
get { return _reader[i]; }
}
public object this[string name]
{
get { return _reader[name]; }
}
public bool NextResult()
{
return _reader.NextResult();
}
public bool Read()
{
return _reader.Read();
}
public int RecordsAffected
{
get { return _reader.RecordsAffected; }
}
}
我仍然会采用第一种方法,除非你真的需要解雇Disposed事件。
答案 1 :(得分:0)
您需要将SqlConnection / SqlCommand初始化移出ExecuteDataReaderAsync
方法(使包装有点无意义)或逐步浏览所有数据,并存储值。
这是一种方法:
public List<Dictionary<string, object>> ExecuteDataReaderAsync(string connectionString, CommandType cmdType, string spName, params SqlParameter[] cmdParameters) {
//TODO make async once fixed problem
var records = new List<Dictionary<string, object>>();
using (var conn = new SqlConnection(connectionString)) {
conn.Open();
using (var cmd = new SqlCommand(spName, conn)) {
cmd.CommandType = cmdType;
cmd.Parameters.AddRange(cmdParameters);
using (var rdr = cmd.ExecuteReader(CommandBehavior.Default)) {
while (rdr.Read()) {
var record = new Dictionary<string, object>();
for (int fieldIndex = 0; fieldIndex < rdr.FieldCount; fieldIndex++) {
record.Add(rdr.GetName(fieldIndex), rdr.GetValue(fieldIndex));
}
records.Add(record);
}
}
}
}
return results;
}
不幸的是,我目前无法对此进行测试。但它应该接近正确。