Почему соединение должно быть открыто для запроса, но не для заполнения набора данных?

Когда я подключаюсь к источнику данных SQL в своем приложении C #, я могу заполнить набор данных, используя следующий код. Обратите внимание, что я не обнаруживаю явного подключения к источнику данных.

SqlConnection cw_con = new SqlConnection("Server=Server;Database=Database;User=User;password=password"); SqlCommand cmd = new SqlCommand("SELECT * FROM Example WHERE value = value"); cmd.Connection = cw_con; //Create DataSet DataSet cw_ds = new DataSet("cw_ds"); SqlDataAdapter da = new SqlDataAdapter(); da.SelectCommand = cmd; //Execute Command and Fill DataSet da.Fill(cw_ds); cw_ds.Clear(); 

Однако, если я хочу выполнить запрос, например INSERT INTO или UPDATE почему я должен явно открыть соединение, используя connection.Open(); ?

 SqlConnection cw_con = new SqlConnection("Server=Server;Database=Database;User=User;password=password"); cw_con.Open(); SqlCommand cmd = new SqlCommand("UPDATE example SET value = value WHERE value = value"); cmd.Connection = cw_con; cmd.ExecuteNonQuery(); cw_con.Close(); 

Это связано с тем, что DataAdapter открывает соединение неявно, когда он закрыт изначально. Затем он закроет его, если он был закрыт раньше, иначе соединение останется открытым.

Из MSDN :

Метод Fill извлекает данные из источника данных с помощью инструкции SELECT. Объект IDbConnection, связанный с командой select, должен быть действительным, но он не должен быть открытым. Если IDbConnection закрыт до вызова Fill, он открывается для извлечения данных и затем закрывается. Если соединение открыто до вызова Fill, оно остается открытым.

При использовании SqlCommand вы должны открыто открывать и закрывать соединения самостоятельно.

В качестве примечания :

  1. Использовать параметры, чтобы избежать SQL-инъекций
  2. Используйте using-statement для чего-либо, реализующего IDisposable , особенно Connections, поскольку он гарантирует, что он будет удален или закрыт как можно скорее, даже в случае ошибки

Из документации DataAdapter.Fill

Если соединение закрыто до вызова Fill, оно открывается для извлечения данных, а затем закрывается. Если соединение открыто до вызова Fill, оно остается открытым.

Когда вы используете SqlCommand, вы используете класс более низкого уровня, поэтому вы должны сами управлять этим соединением.

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

 SqlCommand InsertCmd = new ("Insert statement", cw_con) cw_con.Open(); foreach (var newitem in collection) { --Set Parameters UpdateCmd.ExecuteNonQuery(); } cw_con.Close(); 

В документации указывается, что

Метод Fill извлекает строки из источника данных, используя оператор SELECT, указанный соответствующим свойством SelectCommand. Объект соединения, связанный с оператором SELECT, должен быть действительным, но его не нужно открывать. Если соединение закрыто до вызова Fill, оно открывается для извлечения данных, а затем закрывается. Если соединение открыто до вызова Fill, оно остается открытым.

Посмотрите здесь для получения дополнительной информации.