Возникли проблемы с: Соединение не было закрыто. Текущее состояние соединения открыто. - SQL Сервер & C# - PullRequest
0 голосов
/ 30 января 2020

В настоящее время я работаю над формой входа в систему управления школой. Дело в том, что при попытке войти я получаю сообщение об ошибке:

System.InvalidOperationException: соединение не было закрыто. Текущее состояние соединения открыто

Это говорит о том, что ошибка в 30-й строке кода, но я не могу найти способ ее решить.

Вот код метода, в котором происходит ошибка:

public void LoginTeacher()
{
        try
        {
            command = new SqlCommand("TeacherLogin", connection);
            command.CommandType = CommandType.StoredProcedure;

            connection.Open(); // This is the 30th line. 

            command.Parameters.AddWithValue("@username", Txt_User.Text);
            command.Parameters.AddWithValue("@password", Txt_Pass.Text);

            SqlDataReader dataReader = command.ExecuteReader();

            if (dataReader.Read())
            { 
                    TeacherDash teacherDash = new TeacherDash();
                    this.Hide();
                    teacherDash.lblusertype.Text = dataReader[1] + " " + dataReader[2].ToString();
                    teacherDash.ShowDialog();
                    this.Close();
                }
        }
        catch (Exception ex)
        {
            MessageBox.Show(ex.ToString());
        }
        finally
        {
            connection.Close();
        }
}

Сразу после того, как эта ошибка показана, есть еще один, который говорит:

Система .InvalidOperationException: Неверная попытка вызвать CheckDataIsReady, когда читатель закрыт

и указывает на строку 71, которая выглядит следующим образом:

public void Login()
{
        try
        {
            command = new SqlCommand("SP_USER_LOGIN", connection);
            command.CommandType = CommandType.StoredProcedure;

            connection.Open();

            command.Parameters.AddWithValue("@user", Txt_User.Text);
            command.Parameters.AddWithValue("@pass", Txt_Pass.Text);

            SqlDataReader dataReader = command.ExecuteReader();

            if (dataReader.Read())
            {
                LoginTeacher();

                if (dataReader[10].Equals("Admin"))
                {
                    AdminDash adminDash = new AdminDash();
                    this.Hide();
                    adminDash.lblusertype.Text = dataReader[1] + " " + dataReader[2].ToString();
                    adminDash.ShowDialog();

                    this.Close();
                }

После этого есть больше кода, но я не делаю считаю это актуальным, поскольку это то же самое, но с другим типом пользователей.

Заранее спасибо!

Ответы [ 2 ]

1 голос
/ 30 января 2020

Вы можете попробовать изменить метод TeacherLogin () на что-то вроде следующего:

public void TeacherLogin()
{
    try
    {
        using(SqlConnection con = new SqlConnection("connection string"))
        {
            using(SqlCommand cmd = new SqlCommand("TeacherLogin"))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.AddWithValue("@username", Txt_User.Text);
                cmd.Parameters.AddWithValue("@password", Txt_Pass.Text);
                cmd.Connection = con;
                con.Open();
                using(SqlDataReader dr = cmd.ExecuteReader())
                {
                    while(dr.Read())
                    {
                        TeacherDash teacherDash = new TeacherDash();
                        this.Hide();
                        teacherDash.lblusertype.Text = string.Format("{0} {1}", dr[1], dr[2]);
                        teacherDash.ShowDialog();
                    }
                }
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
}

Нет необходимости использовать finally {}, чтобы закрыть соединение, так как все оно заключено в блок using (), он закроется и удалится самостоятельно, когда код покинет блок. Я бы всегда рекомендовал использовать SQL соединения и команды таким образом, так как это может привести к проблемам, если соединения остаются открытыми.

0 голосов
/ 02 февраля 2020

Объект базы данных должен быть закрыт и утилизирован. Хранение их локально по отношению к методу, в котором они используются, позволяет вам убедиться в этом. Использование блоков позаботится об этом за вас.

Я использовал DataTable вместо тестирования с помощью считывателя, потому что соединение должно оставаться открытым, пока он используется. Важно открывать и закрывать соединение в кратчайшие сроки.

Пожалуйста, не используйте .AddWithValue. См. http://www.dbdelta.com/addwithvalue-is-evil/ и https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/ и еще один: https://dba.stackexchange.com/questions/195937/addwithvalue-performance-and-plan-cache-implications Вот еще один https://andrevdm.blogspot.com/2010/12/parameterised-queriesdont-use.html Конечно, у вас будет чтобы проверить в вашей базе данных реальные типы данных и размер поля, чтобы иметь правильный метод .Add.

    public void LoginTeacher()
    {
        DataTable dt = new DataTable();
        using (SqlConnection cn = new SqlConnection("your connection string"))
        using (SqlCommand cmd = new SqlCommand("TeacherLogin", cn))
        { 
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add("@username",SqlDbType.VarChar,100 ).Value = Txt_User.Text;
            cmd.Parameters.Add("@password",SqlDbType.VarChar, 100 ).Value =Txt_Pass.Text;
            cn.Open();
            dt.Load(cmd.ExecuteReader());
        } //Your connection and command are both disposed
        if (dt.Rows.Count > 0)
        {
            TeacherDash teacherDash = new TeacherDash();
            teacherDash.lblusertype.Text = $"{dt.Rows[0][1]} {dt.Rows[0][2]}";
            teacherDash.ShowDialog();
            Close();
        }
        else
            MessageBox.Show("Sorry, login failed");
    }
...