Как отслеживать изменения таблицы SQL Server с помощью c #? - PullRequest
60 голосов
/ 13 марта 2011

У меня есть несколько приложений, обращающихся к одной и той же БД, и мне нужно получать уведомление, если одно из этих приложений что-либо меняет (обновляет, вставляет) в определенной таблице.

База данных и приложения не совпадаютсервер.

Ответы [ 10 ]

50 голосов
/ 13 марта 2011

Вы можете использовать SqlDependency Class. Он предназначен главным образом для страниц ASP.NET (небольшое количество клиентских уведомлений).

ALTER DATABASE UrDb SET ENABLE_BROKER

Реализуйте событие OnChange, чтобы получать уведомления:

void OnChange(object sender, SqlNotificationEventArgs e)

И в коде:

SqlCommand cmd = ...
cmd.Notification = null;

SqlDependency dependency = new SqlDependency(cmd);

dependency.OnChange += OnChange;

Он использует Service Broker (коммуникационная платформа на основе сообщений) для получения сообщений от механизма базы данных.

28 голосов
/ 15 августа 2017

В интересах полноты существует пара других решений, которые, на мой взгляд, являются более ортодоксальными и устоявшимися, чем решения, основанные на классах SqlDependency (и SqlTableDependency).SqlDependency был разработан для обновления кэша веб-сервера, поэтому он не обеспечивает такой устойчивости при нагрузке, которую вы бы требовали от производителя событий.

В целом есть еще четыре параметра, которые здесь еще не упомянуты:

  • Отслеживание изменений
  • CDC
  • Триггеры в очереди
  • CLR

Отслеживание изменений

Источник: https://docs.microsoft.com/en-us/sql/relational-databases/track-changes/about-change-tracking-sql-server

Отслеживание изменений - это упрощенный механизм уведомлений на SQL-сервере.По сути, номер версии всей базы данных увеличивается с каждым изменением любых данных.Затем номер версии записывается в таблицы отслеживания изменений с битовой маской, включающей имена столбцов, которые были изменены.Обратите внимание, что фактическое изменение не сохраняется.Уведомление содержит только информацию о том, что конкретный объект данных изменился.Кроме того, поскольку управление версиями таблицы изменений является накопительным, уведомления об изменениях для отдельных элементов не сохраняются и перезаписываются более новыми уведомлениями.Это означает, что если сущность изменяется дважды, отслеживание изменений будет знать только о самых последних изменениях.

Чтобы зафиксировать эти изменения в c #, необходимо использовать опрос.Таблицы отслеживания изменений могут быть опрошены, и каждое изменение может быть проверено, чтобы увидеть, представляет ли он интерес.Если это представляет интерес, необходимо затем перейти непосредственно к данным, чтобы получить текущее состояние.

Сбор данных изменений

Источник: https://technet.microsoft.com/en-us/library/bb522489(v=sql.105).aspx

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

Аналогично отслеживанию изменений, чтобы зафиксировать эти изменения в c #, необходимо использовать опрос.Однако в случае CDC информация об опросе будет содержать детали изменения, поэтому нет необходимости возвращаться к самим данным.

Триггеры в очереди

Источник: https://code.msdn.microsoft.com/Service-Broker-Message-e81c4316

Этот метод зависит от триггеров на таблицах, из которых требуются уведомления.Каждое изменение запускает триггер, и триггер записывает эту информацию в очередь компонента Service Broker.Затем к очереди можно подключиться через C # с помощью обработчика сообщений Service Broker (пример по ссылке выше).

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

CLR

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

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

1055 * Резюмируя ... 1059 * Он всегда был источником удивления мне, что Microsoft упорно отказывается решать эту проблему пространства.Событие из базы данных в код должно быть встроенной функцией продукта базы данных.Учитывая, что Oracle Advanced Queuing в сочетании с событием ODP.net MessageAvailable предоставили надежную базу данных для C # более, чем 10 лет назад , это ужасно от MS.

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

17 голосов
/ 13 марта 2011

Обычно вы используете Service Broker

Это триггер -> очередь -> приложение (я)

Изменить, увидев другие ответы:

К вашему сведению: «Уведомления о запросах» построены на компоненте Service Broker

Edit2:

Дополнительные ссылки

8 голосов
/ 09 сентября 2015

Использовать SqlTableDependency.Это AC # компонент, вызывающий события при изменении записи.Другие подробности можно найти по адресу: https://github.com/christiandelbianco/monitor-table-change-with-sqltabledependency

Это похоже на .NET SqlDependency за исключением того, что SqlTableDependency вызывает события, содержащие измененные / удаленные или обновленные значения таблицы базы данных:

string conString = "data source=.;initial catalog=myDB;integrated security=True";

using(var tableDependency = new SqlTableDependency<Customers>(conString))
{
    tableDependency.OnChanged += TableDependency_Changed;
    tableDependency.Start();

    Console.WriteLine("Waiting for receiving notifications...");
    Console.WriteLine("Press a key to stop");
    Console.ReadKey();
}
...
...
void TableDependency_Changed(object sender, RecordChangedEventArgs<Customers> e)
{
    if (e.ChangeType != ChangeType.None)
    {
        var changedEntity = e.Entity;
        Console.WriteLine("DML operation: " + e.ChangeType);
        Console.WriteLine("ID: " + changedEntity.Id);
        Console.WriteLine("Name: " + changedEntity.Name);
        Console.WriteLine("Surname: " + changedEntity.Surname);
    }
}
6 голосов
/ 23 марта 2016

SqlDependency не наблюдает за базой данных, он наблюдает указанную вами SqlCommand, поэтому, если вы пытаетесь позволить, скажем, вставить значения в базу данных в 1 проекте и захватить это событие в другом проекте, оно не будет работать, потому что событие было из SqlCommand из проекта 1º, а не база данных, потому что при создании SqlDependency вы связываете его с SqlCommand, и только когда эта команда из этого проекта используется, она создает событие Change.

6 голосов
/ 26 января 2015

Будьте осторожны, используя SqlDependency класс - у него проблемы с утечками памяти.

Просто используйте кроссплатформенное решение, совместимое с .NET 3.5, .NET Core и с открытым исходным кодом - SqlDependencyEx .Вы можете получать уведомления, а также данные, которые были изменены (вы можете получить доступ к ним через свойства в объекте события уведомления).Вы также можете добавить операции DELETE \ UPDATE \ INSERT по отдельности или вместе.

Вот пример того, как просто использовать SqlDependencyEx :

int changesReceived = 0;
using (SqlDependencyEx sqlDependency = new SqlDependencyEx(
          TEST_CONNECTION_STRING, TEST_DATABASE_NAME, TEST_TABLE_NAME)) 
{
    sqlDependency.TableChanged += (o, e) => changesReceived++;
    sqlDependency.Start();

    // Make table changes.
    MakeTableInsertDeleteChanges(changesCount);

    // Wait a little bit to receive all changes.
    Thread.Sleep(1000);
}

Assert.AreEqual(changesCount, changesReceived);

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

4 голосов
/ 13 марта 2011

Начиная с SQL Server 2005, у вас есть возможность использовать Уведомления о запросах , которые могут быть использованы ADO.NET, см. http://msdn.microsoft.com/en-us/library/t9x04ed2.aspx

2 голосов
/ 13 марта 2011

выглядит как плохая архитектура.Кроме того, вы не указали тип приложения, о котором нужно уведомить (веб-приложение / консольное приложение / winforms / service и т. д.)

тем не менее, чтобы ответить на ваш вопрос, существует несколько способов решения этой проблемы.Вы можете использовать:

1) отметки времени, если вы просто заинтересованы в том, чтобы следующий набор обновлений из второго приложения не конфликтовал с обновлениями из первого приложения

2) объект зависимости sql -см. http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx для получения дополнительной информации

3) настраиваемой службы push-уведомлений, на которую несколько клиентов (web / winform / service) могут подписаться и получать уведомления об изменениях

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

1 голос
/ 13 августа 2014

Другой, очень простой способ мониторинга таблиц - управление версиями таблиц.Система доказала свою работоспособность в таких конструкциях, как синхронизация DNS.Чтобы это работало, вы создаете таблицу, содержащую имена таблиц и версии таблиц как decimal или bigint.. В каждой таблице, которую необходимо отслеживать, создайте триггер при вставке, обновлении и удалении, который будет увеличивать соответствующую версию таблицы в таблице версий при выполнении.Если вы ожидаете, что какие-либо из отслеживаемых таблиц будут часто изменяться, вам необходимо обеспечить повторное использование версий.Наконец, в вашем приложении каждый раз, когда вы запрашиваете отслеживаемую таблицу, вы также запрашиваете ее версию и сохраняете ее.Когда вы собираетесь изменить отслеживаемую таблицу из вашего приложения, вы сначала запрашиваете ее текущую версию и обрабатываете изменения, только если версия не изменилась.Вы можете хранить proc на сервере sql, чтобы сделать эту работу за вас.Это чрезвычайно простое, но проверенное твердое решение.Он имеет конкретное функциональное использование (для обеспечения согласованности данных) и не требует значительных ресурсов (вы не генерируете брокерские события, которые вы бы не отслеживали), но ему необходимо приложение для активной проверки изменений, а не для пассивного ожидания события.

0 голосов
/ 21 октября 2018

реализация Голанга из ServiceBrokerListener для других языков с использованием AMQP enter image description here

...