C#中使用IDataReader时遭遇IndexOutOfRangeException问题求助
问题:IDataReader调用GetDataValue时触发IndexOutOfRangeException异常
我在C#中使用IDataReader时遇到了IndexOutOfRangeException异常,该异常在执行GetDataValue方法时触发。
示例代码
业务查询方法
public List<Users> SelectUsersbyUsernamePassword(string username, string password) { const string SQL_STATEMENT = "SELECT U.Username, U.Password, U.Role " + "FROM Users U "; List<Users> listusers = new List<Users>(); Database db = new Microsoft.Practices.EnterpriseLibrary.Data.Sql.SqlDatabase(CONNECTION_NAME); using (DbCommand cmd = db.GetSqlStringCommand(SQL_STATEMENT)) { db.AddInParameter(cmd, "@username", DbType.String, username); db.AddInParameter(cmd, "@password", DbType.String, password); try { using (IDataReader dr = db.ExecuteReader(cmd)) { while (dr.Read()) { Users users = new Users(); users.UserID = base.GetDataValue<int>(dr, "UserID"); users.Username = base.GetDataValue<string>(dr, "Username"); users.Password = base.GetDataValue<string>(dr, "Password"); users.Role = base.GetDataValue<string>(dr, "Role"); listusers.Add(users); } } } catch (Exception ex) { throw ex; //throw new DbException(ex.Message, SQL_STATEMENT, "username = " + username, ex.InnerException); } } return listusers; }
数据访问基础方法
protected T GetDataValue<T>(IDataReader dr, string columnName) { int i = dr.GetOrdinal(columnName); if (!dr.IsDBNull(i)) return (T)dr.GetValue(i); else return default(T); }
问题原因分析
- 直接触发异常的原因:SQL查询语句中只选择了
Username、Password、Role三列,但代码中尝试读取UserID字段,GetOrdinal方法在找不到对应列名时会抛出IndexOutOfRangeException。 - 附加逻辑问题:SQL语句未添加WHERE条件,当前会返回所有用户数据,完全没有利用传入的username和password参数做过滤,业务逻辑不符合预期。
修复方案
1. 修正SQL查询语句
补充UserID列的选择,并添加WHERE条件过滤用户:
const string SQL_STATEMENT = "SELECT U.UserID, U.Username, U.Password, U.Role " + "FROM Users U " + "WHERE U.Username = @username AND U.Password = @password";
2. (可选)增强GetDataValue的容错性
如果希望方法在列不存在时不抛出异常,可以增加列名存在性检查:
protected T GetDataValue<T>(IDataReader dr, string columnName) { // 检查列是否存在于结果集中 if (!dr.GetSchemaTable().AsEnumerable().Any(row => row["ColumnName"].ToString() == columnName)) return default(T); int i = dr.GetOrdinal(columnName); if (!dr.IsDBNull(i)) return (T)dr.GetValue(i); else return default(T); }
内容的提问来源于stack exchange,提问作者RogerSK
相关产品推荐
相关产品推荐

