SQLConnection с оператором Using, вызывающим SQLDataReader изнутри?

Просто хочу убедиться, что это лучший способ вызвать соединение и получить данные из базы данных, или мне следует каким-то образом вызвать средство чтения данных вне оператора использования? (чтобы соединение закрывалось быстрее?) или есть ли что-то, что вы лично изменили бы в этом?

using (SqlConnection cn = new SqlConnection(connStr))
        {
            using (SqlCommand cm = new SqlCommand(connStr, cn))
            {  
                cm.CommandType = CommandType.StoredProcedure;
                cm.CommandText = "GetExchRatesByDate";
                cm.Parameters.Add("@Date", SqlDbType.VarChar).Value = txtStartDate.Text;
                cn.Open();
                SqlDataReader dr = cm.ExecuteReader();

                while (dr.Read())
                {
                    firstName = (string)dr["GivenName"];
                    lastName = (string)dr["sn"];;
                }
                dr.Close();
            }
        }

person Spooks    schedule 17.12.2010    source источник


Ответы (5)


Вы не можете успешно вызвать datareader вне оператора using, так как для чтения данных требуется открытое соединение.

Соединение закроется достаточно быстро, как у вас, и даже не «закроется». Он будет возвращен в пул соединений (при условии, что вы его используете). Поскольку вы, вероятно, так и делаете, вам не нужно беспокоиться о том, как быстро соединение закрывается в этом контексте, поскольку другие части приложения, которым требуется соединение, захватят доступное соединение из пула. Это предполагает, что у вас нет приложения с действительно высоким трафиком, это может стать важным в этом сценарии, но это много, много, много одновременных пользователей, и вы можете решить эту проблему, увеличив количество подключений в пуле. .

Крис также упомянул хороший момент: это должно быть в операторе использования:

  SqlDataReader dr = cm.ExecuteReader();

                while (dr.Read())
                {
                    firstName = (string)dr["GivenName"];
                    lastName = (string)dr["sn"];;
                }
                dr.Close();

В этом случае, если ваш ридер сгенерирует исключение, он никогда не доберется до dr.Close();, поэтому он останется открытым намного дольше, чем нужно (возможно, даже на время жизни приложения).

Считыватель данных

person kemiller2002    schedule 17.12.2010
comment
спасибо, просто хотел убедиться, что это приемлемый способ получения данных. Я буду продолжать использовать этот код - person Spooks; 17.12.2010

Мало того, что вы не можете сделать вызов SqlDataReader вне оператора using, так как все объявленные внутри переменных будут удалены, и вам нужно открытое соединение для чтения данных, вам лучше написать объект, который будет возвращен, или даже список вашего объекта.

public class MyObject {
    public string FirstName { get; set; }
    public string Surname { get; set; }
}

public IEnumerable<MyObject> GetObjects() {
    ICollection<MyObject> myObjects = new List<MyObject>();

    using (SqlConnection cn = new SqlConnection(connStr))
    {
        using (SqlCommand cm = new SqlCommand(connStr, cn))
        {  
            cm.CommandType = CommandType.StoredProcedure;
            cm.CommandText = "GetExchRatesByDate";
            cm.Parameters.Add("@Date", SqlDbType.VarChar).Value = txtStartDate.Text;
            cn.Open();

            using(SqlDataReader dr = cm.ExecuteReader()) 
                while (dr.Read()) {
                    MyObject myObject = new MyObject();
                    myObject.FirstName = (string)dr["GivenName"];
                    myObject.Surname = (string)dr["sn"];
                    myObjects.Add(myObject);
                }
        }
    }
    return myObjects;
}
person Will Marcouiller    schedule 17.12.2010

Средство чтения данных реализует IDisposable, поэтому его также следует обернуть в предложение using. Все остальное выглядит хорошо.

person NotMe    schedule 17.12.2010

Другие рассмотрели это, но еще одна вещь, которую я люблю использовать, это AddWithValue:

cm.Parameters.Add("@Date", SqlDbType.VarChar).Value = txtStartDate.Text;

может быть записано как:

cm.Parameters.AddWithValue("@Date", txtStartDate.Text);
person Marcie    schedule 17.12.2010

Я бы подумал о том, чтобы включить SQLConnection в фабричный метод. (если это называется нагрузками)

Также у меня не было бы цикла while вокруг dr.Read. Вы ожидаете только один ответ, так что же происходит, когда нет результатов или много результатов???? Не слишком уверен, нравится ли мне кастинг, но, наверное, хорошо.

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

Ваши операторы использования выглядят хорошо для меня.

person Angus Connell    schedule 17.12.2010