IndexOutOfRange Исключение в sqldatareader с использованием c # - PullRequest
0 голосов
/ 04 мая 2018

Я создаю приложение, используя c #, В моем интерфейсе аутентификации у меня есть тестовый элемент управления, я хочу знать профиль пользователя.

Моя база данных содержит таблицу с именем user, которая содержит 4 столбца

(id_user,name ,mail, profile) 

Вот мой код

public string profil_user(string login)
    {
        SqlConnection conn = new database().connect_user();
        SqlCommand cmd = conn.CreateCommand();
        cmd.CommandText = "select profile from user where name = '" + login + "';";
        SqlDataReader s = cmd.ExecuteReader();
        if (s.Read())
        {
           return ( s.GetString(3));


        }
        else{return ("false"); }
    }

но у меня есть исключение в s.GetString(3)

system.IndexOutOfRange: индекс находился за пределами массива

Ответы [ 5 ]

0 голосов
/ 04 мая 2018

Итак, вам нужен четвертый ряд, а не четвертый столбец, к которому вы пытаетесь получить доступ s.GetString(3):

int rowNum = 0;
while(s.Read())
{
   if(++rowNum == 4)
   {
      return s.GetString(0);
   }
}
return "false";

Однако немного странно получить доступ к четвертому ряду, когда вы не используете Order By. Вы также должны возвращать только нужную строку с правильным SQL-запросом.

Вы также открыты для внедрения SQL, если здесь используется конкатенация строк:

cmd.CommandText = "select profile from user where name = '" + login + "';";

Использовать параметры sql:

cmd.CommandText = "select profile from user where name = @login";
cmd.Parameters.Add("@login", SqlDbType.VarChar).Value = login;

имеет 4 столбца, а не строки

Хорошо, значит вы хотите четвертый столбец. Почему вы не используете имя вместо этого?

Поскольку вы выбираете только столбец profile (четвертый), вы можете просто использовать GetString(0). Но вы также можете выбрать все столбцы и затем определить правильный индекс с помощью GetOrdinal:

int profileColumnIndex = s.GetOrdinal("profile");
return s.GetString(profileColumnIndex);

Это полезно, если вы не управляете запросом или он может быть изменен в будущем.

0 голосов
/ 04 мая 2018

Параметр для SqlDataReader.GetString должен быть индексом столбца. Вы выбираете только один столбец, поэтому вы получаете исключение.

0 голосов
/ 04 мая 2018

Поскольку у вас нет всех полей в списке выбора

Измените SQL на:

select id_user,name ,mail, profile from user where name = '" + login + "';
0 голосов
/ 04 мая 2018

Вы выбираете только 1 поле, таким образом, индекс 3 выходит за пределы. Также очень важно использовать параметры. Попробуйте:

cmd.CommandText = "select profile from user where name = @login;";
cmd.Parameters.Add("@login, SqlDbType.NVarChar).Value = login;
SqlDataReader s = cmd.ExecuteReader();
while (s.Read())
{   
  return  s[0].ToString();
}
0 голосов
/ 04 мая 2018

Вы выбираете только одно поле (profile), но затем вы пытаетесь выбрать 4-е поле (индекс 3) здесь:

return ( s.GetString(3));

В дополнение к простому возвращению s.GetString(0) я бы настоятельно посоветовал вам:

  • Использовать параметризованный SQL - всегда сделать это, чтобы предотвратить атаки SQL-инъекций , сделать ваш код более читабельным и предотвратить непредвиденные проблемы преобразования текста
  • Либо сгенерируйте исключение, либо верните null, если профиль не найден, вместо того, чтобы возвращать строку "false"
  • Используйте операторы using для одноразовых вещей, таких как SqlCommand, SqlConnection и SqlDataReader, чтобы обеспечить надлежащую очистку ресурсов
  • Начните следовать Соглашения об именах .NET , чтобы сделать ваш код более идиоматичным

Так что-то вроде:

public string GetUserProfile(string login)
{
    string sql = select profile from user where name = @login";
    // I assume Connect() returns an *open* connection?
    using (var conn = new Database().Connect())
    {
        using (var command = new SqlCommand(sql, conn))
        {
            command.Parameters.Add("@login", SqlDbType.NVarChar).Value = login;
            using (var reader = command.ExecuteReader())
            {
                // If it's an error (code failure) for there to be no matching profile,
                // you may want to throw an exception instead.
                return s.Read() ? s.GetString(0) : null;
            }
        }
    }
}
...