2016-05-25 4 views
10

У меня есть следующий код:Когда называется DbConnection.StateChange?

class Program 
{ 
    static void Main() 
    { 
     var connection = new SqlConnection("myConnectionString"); 
     connection.Open(); 
     connection.StateChange += HandleSqlConnectionDrop; 
     Console.WriteLine("Hi"); 
     Console.ReadLine(); 
    } 

    private static void HandleSqlConnectionDrop(object connection, StateChangeEventArgs args) 
    { 
     Console.WriteLine("DB change detected"); 
    } 
} 

я начинаю выше код, когда экземпляр SQL-сервер. Затем я приступаю к исполнению

SHUTDOWN WITH NOWAIT; 

на сервере sql-сервера, к которому подключена программа. Затем я наблюдаю остановку службы SQL-сервера. Тем не менее, я никогда не вижу сообщение «обнаружено изменение БД» на выходе. Почему это?

Кроме того: Я увижу, что обработчик StateChange вызывается, если я затем попытаюсь выполнить операцию над SQL-соединением, но никогда раньше. Есть ли способ изменить это поведение?

+0

«Я увижу обработчик StateChange, если я попытаюсь выполнить операцию над SQL-соединением» - на самом деле вы отвечаете на свой вопрос. Объект подключения не поддерживает сервер ping и проверяет состояние только при необходимости. Поместите 'connection.Open()' после '.StateChange + = ...', чтобы увидеть, что он работает. –

+0

@AlexKudryashev Не должно ли существовать какая-то поддержка между SQL-клиентом и SQL-сервером? Я понимаю, что объекты SqlConnection должны сопоставлять индивидуальные сеансы SQL-сервера. Если сервер убивает сеанс, есть ли способ, которым я могу передать эту информацию в мой код? –

+0

, вы можете попробовать опробовать сервер с чем-то безвредным, например 'select 1' –

ответ

3

Событие StateChange предназначено для состояния соединения, а не экземпляра сервера базы данных. Для того, чтобы получить состояние сервера базы данных,

Событие StateChange происходит, когда состояние события изменяется от закрыты открыт, или открытый на закрытое.

Из MSDN: https://msdn.microsoft.com/en-us/library/system.data.common.dbconnection.statechange(v=vs.110).aspx

Если вы собираетесь свернуть свой собственный монитор для базы данных, то вы можете рассмотреть возможность использования метода, который возвращает истина/ложь, если соединение доступно и пинг этот метод на расписание. Вы могли бы даже обернуть метод, чтобы сделать это в бесконечном цикле, повторяющемся после продолжительности времени, и поднять его собственное событие, когда это «состояние» действительно изменится.

Вот быстрый метод из другого SO ответить, что это простой подход:

/// <summary> 
/// Test that the server is connected 
/// </summary> 
/// <param name="connectionString">The connection string</param> 
/// <returns>true if the connection is opened</returns> 
private static bool IsServerConnected(string connectionString) 
{ 
    using (SqlConnection connection = new SqlConnection(connectionString)) 
    { 
     try 
     { 
      connection.Open(); 
      return true; 
     } 
     catch (SqlException) 
     { 
      return false; 
     } 
    } 
} 

Источник: https://stackoverflow.com/a/9943871/4154421

+0

«Событие StateChange предназначено для состояния соединения, а не для экземпляра сервера базы данных». -> Но если состояние сервера меняется, то состояние соединения также должно измениться (т.е. перестать функционировать). –

+0

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

8

Когда DbConnection.StateChange называется?

Вы можете узнать, посмотрев исходный код ссылки Microsoft.

Событие StateChange вызвано функцией DbConnection.OnStateChange. Поиск ссылок на эту функцию дает лишь несколько примеров:

Во-первых, в классе SqlConnectionOnStateChange вызывается только в методе Close.

Тогда в файле DbConnectionHelper.cs есть частичный класс, называемый DBCONNECTIONOBJECT. Похоже, что он используется для всех классов DbConnection, используя некоторые махинации времени сборки. Поэтому вы можете считать его частью SqlConnection. В любом случае он вызывает OnStateChange только с функции SetInnerConnectionEvent.

Насколько я могу судить (неполный класс ерунды затрудняет), SqlConnection.SetInnerConnectionEvent вызывается только от SqlConnectionFactory.SetInnerConnectionEvent, что вызывается из:

Так, в целом - это событие только поднятый в ответ на стороне клиента действий - там нет как представляется, любой опрос состояния подключения, встроенный в SQLConnection.

Есть ли способ изменить это поведение?

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