【问题标题】:Getting an IndexOutOfRangeException when putting sql into an object array将 sql 放入对象数组时出现 IndexOutOfRangeException
【发布时间】:2019-02-21 14:12:17
【问题描述】:

目前正在为我工​​作的公司开发一个小工具,该工具将处理数据库。我有几个类处理各种 SQL 函数,但每当我尝试将数据库中的特定数据放入 datagridview 时,我都会收到异常。

SQL函数:

public class OUsersDB
{
    SqlConnection conn = new SqlConnection("Connection Information");

    public SqlDataReader Select()
    {
        conn.Open();
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = "SELECT au.ApplicationId, au.UserId, au.UserName, au.MobileAlias, au.LastActivityDate, au.Name, sms.number, am.email FROM aspnet_users AS au " +
            " JOIN aspnet_membership AS am ON au.userid=am.userid " +
            " JOIN smsphonebooks AS sms ON au.name=sms.name";
        SqlDataReader ur = cmd.ExecuteReader();
        return ur;

    }
}

Winform 数据网格函数

        public void Usersdb()
    {
        OUsersDB oudb = new OUsersDB();
        SqlDataReader ur = oudb.Select();
        myDataUsers.Rows.Clear();
        while (ur.Read())
        {
            object[] objUsers = {
                ur["au_ApplicationId"].ToString(),
                ur["au_UserId"].ToString(),
                ur["au_UserName"].ToString(),
                ur["au_MobileAlias"].ToString(),
                ur["au_LastActivityDate"].ToString(),
                ur["au_Name"].ToString(),
                ur["au_Phone"].ToString(),
                ur["au_Email"].ToString(), };
            myDataUsers.Rows.Add(objUsers);
            conn.Close();
        }

我在代码中有一个类似的 sql 函数和对象数组,加载得很好,但是一旦到达这部分,我就会在

ur["au_ApplicationId"].ToString(),

它只是说

System.IndexOutOfRangeException: 'au_ApplicationId'

【问题讨论】:

  • 选择au.ApplicationId 字段并尝试从阅读器获取au_ApplicationId
  • 该列不应该只命名为“ApplicationId”吗?尝试删除“au_”。其他列也一样。
  • 为什么不直接使用SqlDataAdapter.Fill(DataTable)?不知道你为什么要在这里手动填写DataTable myDataUsers

标签: c# sql winforms datagridview


【解决方案1】:

更改 obj 以读取没有别名的列。您仅使用别名来引用查询中的列,但查询的输出不会有别名。

while (ur.Read())
        {
            object[] objUsers = {
                ur["ApplicationId"].ToString(),
                ur["UserId"].ToString(),
                ur["UserName"].ToString(),
                ur["MobileAlias"].ToString(),
                ur["LastActivityDate"].ToString(),
                ur["Name"].ToString(),
                ur["Phone"].ToString(),
                ur["Email"].ToString(), };
            myDataUsers.Rows.Add(objUsers);
            conn.Close();
        }

【讨论】:

  • 我之前确实尝试过不使用别名,但仍然得到相同的响应。
  • 您是否检查过此查询是否返回任何行?在while 之前使用if (reader.HasRows) {
  • 这实际上是错误的,它是您应该用来查找数据而不是原始列名的别名。
  • @RobinSalih 你错了。我说的是 TABLE 别名,而不是 COLUMN 别名。 au 是 TABLE 别名,在最终结果中被省略,而 OP 没有在他的查询中放置任何 COLUMN 别名,而是使用原始的 COLUMN 名称。更好地阅读代码。
  • @Stormhashe 对不起,是的,你是对的,我认为这些列被别名了。
【解决方案2】:

检查你是否得到任何对象,也许你什么都没有。

【讨论】:

  • 如果他们没有返回数据,那么它不会进入抛出异常的while循环。
【解决方案3】:

你可以试试这个:

https://stackoverflow.com/a/8656011/8512753

或删除表别名

ur["au_ApplicationId"].ToString(),

变成

ur["ApplicationId"].ToString(),

并尝试为 SQL 中返回的列分配具体值

SELECT ApplicationId = au.ApplicationId, ...

【讨论】:

    【解决方案4】:

    关于IndexOutOfRangeException,这是由于试图访问阅读器中不存在的列。当SELECT 语句未执行此操作时,不确定为什么要在列前加上“au_”前缀。

    我会改用SqlDataAdapter 并将此方法添加到OUsersDB

    public void FillTable(DataTable table)
    {
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandType = CommandType.Text;
        cmd.CommandText = "SELECT au.ApplicationId, au.UserId, au.UserName, au.MobileAlias, au.LastActivityDate, au.Name, sms.number, am.email FROM aspnet_users AS au " +
            " JOIN aspnet_membership AS am ON au.userid=am.userid " +
            " JOIN smsphonebooks AS sms ON au.name=sms.name";
        using(var adapter = new SqlDataAdapter(cmd))
            adapter.Fill(table)
    }
    

    将调用代码更改为:

    public void Usersdb()
    {
        OUsersDB oudb = new OUsersDB();
        myDataUsers.Rows.Clear();
        oudb.FillTable(myDataUsers);
    }
    

    或者这里有一个简单的解决方法。将您的 SELECT 语句更改为代码所期望的别名列名。

    SELECT au.ApplicationId as au_ApplicationId, au.UserId as au_UserId, au.UserName as au_UserName, 
    au.MobileAlias as au_MobileAlias, au.LastActivityDate as au_LastActivity, au.Name as au_Name, 
    sms.number as au_Phone, am.email as au_Email -- REST OF QUERY UNCHANGED
    

    【讨论】:

    • 虽然没有解决这个问题。顺便说一句,DataAdapter 将为您打开和关闭连接,因此您不必显式打开它。
    • @LarsTech 你是说SqlDataAdapter(或基类)有一个托管对象的终结器?因为上面的代码没有调用Dispose。不知道为什么这不能解决问题。有一个DataTable,他们试图用一个简单的SELECT 填充。这符合要求。
    • 它没有解决范围问题的索引。我没有声称 DataAdapter 处理任何东西。您在上面的代码中不需要conn.Open();。 DataAdapter 将检查连接是否打开,如果未打开,它将打开它。
    • @LarsTech 我指的是您声称它关闭连接而不被处理的说法。我会删除打开的。我也更新了解决异常的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多