Обработать ошибку подключения к БД MS SQL
Есть Boolean функция которая:
Переписана исходя из советов ниже:
public bool checkUser_Login(TextBox logingox)
{
var login = logingox.Text;
string checklogin = $"select count(login_users) from registration where login_users = '{login}'";
using (SqlConnection con = new SqlConnection(connectionString))
{
con.Open();
using (SqlCommand check = new SqlCommand(checklogin, con))
{
check.Parameters.Add("login_users", SqlDbType.VarChar).Value = login;
int result = (int)check.ExecuteScalar();
return result > 0;
}
}
}
Проверяет на совпадения в БД из textBox и возвращает true, в случае если такая запись уже есть, и соответственно false при отсутствии таковой. Я решил это "чудо" использовать в купе с событием TextChanged. Получил примерный код:
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (checkUser_Login(TextBoxLogin) == true)
{
label2.Text = "Пользователь под ником, " + textBox1.Text + ", уже существует!";
button1.Enabled = false;
}else
{
label2.Text = "\0";
}
}
Получается эффект проверки рилтайм если login уже был зарегистрирован. Я получаю соответствующую подсказку, минуя затраты времени на использовании сначала кнопки, а после попыток исправления(про скорость работы ПО при over900000 пользователей не нужно ничего советовать, спасибо). Как обработать в данном виде исключение - отсутствия подключения.
Те. если сервер пал то я получу простое - Подключение отсутствует.
Что имею по итогу:
private async Task<bool> checkUser_Login(TextBox logingox)
{
var login = logingox.Text;
string checklogin = $"select login_users from registration where login_users = '{login}'";
using (var con = new SqlConnection(connectionString))
{
await con.OpenAsync();
using (var check = new SqlCommand(checklogin, con))
{
check.Parameters.Add("login_users", SqlDbType.VarChar).Value = login;
var result = (string)await check.ExecuteScalarAsync();
return result != null;
}
}
}
Использование:
bool x = await checkUser_Login(textBox1);
if (x) {...}
И не забываем про async в используемом методе.
private async void textBox1_TextChanged(object sender, EventArgs e)
Ответы (2 шт):
Меня немного смущает использование dB.getConnection() для получения коннекта к базе данных. Это как то "не по MS SQL-ному".
Предложу такой вариант:
Пускай у нас есть "строка подключения" (так часто переводят выражение connection string)
Тогда код, соответсвующий приведенному, будет написан примерно так:
const string connStr = "Password=secret_Pa$$w0rD;Persist Security Info=True;User ID=dbuser;Initial Catalog=DB-test;Data Source=sqlsrv,1433;";
private Boolean checkUser_Login()
{
var login_user = textBox1.Text;
string checklogin = $"select login_user from SignIN where login_user = '{login_user}'";
using ( SqlConnection conn = new SqlConnection(connStr) ){
cn.Open();
using (SqlCommand command = new SqlCommand(checklogin, conn)){
SqlDataAdapter adapter = new SqlDataAdapter();
DataTable table = new DataTable();
adapter.SelectCommand = command;
adapter.Fill(table);
if (table.Rows.Count > 0)
{
return true;
}
else
{
return false;
}
}
}
}
Здесь есть одно явное место, где возникнет ошибка, если база данных недоступна - это строка открытия коннекта: cn.Open()
Теперь - давайте рассуждать.
Можно сделать дёшево и сердито: окружить эту конкретную строку
try-catch-ем, и, если в ней возникает ошибка - показывать пользователю MessageBox с сообщением, что база данных недоступна.Но, если подумать, это не очень хорошая стратегия. Это не так хорошо тестируется, как хотелось бы (попробуйте, протестируйте появление MessageBox - поверьте, проверить в тесте Exception - гораздо проще!)
Кроме того, при этом происходит смешивание "уровня интерфейса" (вывод сообщения) и "уровня логики".
Кроме того, пускай, connection к базе мы открыли, но возникла какая то другая ошибка.
В общем, заключить всё взаимодействие с базой в try-catch - это, видимо, лучше, чем обрабатывать его в функции checkUser_Login().
Но тогда понадобится добавить обарботку исключений в то место, откуда происходит вызов. Кроме того, хорошо бы добавить структурированную обработку исключений, чтобы отделить ошибку "недоступности базы" от других, менее вероятных ошибок.
Следующий шаг - это переход к асинхронному взаимодействияю с базой, ну, потому, что это возможно. И там тоже есть свои особенности того, как ведут себя исключения.
Небольшое ревью кода.
Вот это:
if (table.Rows.Count > 0)
{
return true;
}
else
{
return false;
}
заменяется одной строкой:
return table.Rows.Count > 0;
SqlDataAdapter способен сам открыть и закрыть соединение и выполнить запрос.
То есть можно написать просто:
var adapter = new SqlDataAdapter(checklogin, connectionString);
DataTable table = new DataTable();
adapter.Fill(table);
SqlDataAdapter нужен, чтобы загрузить множество данных в DataTable. Между тем, вы запрашиваете из БД одно-единственное значение.
Перепишем код на получение одного значения.
Сделаем это правильно - с применением параметризованного запроса.
private bool CheckUserLogin()
{
string login = loginTextBox.Text;
string checkLogin = $"select login_user from SignIN where login_user = @login";
using var connection = new SqlConnection(_connectionString);
connection.Open();
using var command = new SqlCommand(checkLogin, connection);
command.Parameters.Add("login", SqlDbType.NVarChar).Value = login;
var result = (string)command.ExecuteScalar();
return result != null;
}
Я не знаю, какой именно тип колонки используется у вас в таблице БД. Укажите в коде соответствующий тип SqlDbType.
Более того, нет нужды возвращать из БД логин. Достаточно вернуть некое простое значение, указывающее, что юзер существует. Например:
string checkLogin = $"select count(login_user) from SignIN where login_user = @login";
...
int result = (int)command.ExecuteScalar();
return result > 0;
А теперь, собственно, ответ на вопрос.
Используйте блок try-catch.
Тут может возникнуть следующая проблема: замёрзший интерфейс GUI в случае длительного отсутствия подсоединения к БД.
Для её решения следует использовать асинхронный код.
Что-то вроде:
private async Task<bool> CheckUserLoginAsync()
{
string login = loginTextBox.Text;
string checkLogin = $"select login_user from SignIN where login_user = @login";
await using var connection = new SqlConnection(_connectionString);
await connection.OpenAsync();
await using var command = new SqlCommand(checkLogin, connection);
command.Parameters.Add("login", SqlDbType.NVarChar).Value = login;
var result = (string)await command.ExecuteScalarAsync();
return result != null;
}
Естественно, при вызове этого метода нужно использовать await.
Теперь интерфейс вашего приложения будет отзывчивым.


