Wie kann ich SQL Server-Tabellenänderungen mithilfe von c # überwachen?

76

Ich habe mehr als eine Anwendung, die auf dieselbe Datenbank zugreift, und ich muss benachrichtigt werden, wenn eine dieser Apps etwas in einer bestimmten Tabelle ändert (aktualisieren, einfügen).

Datenbank und Apps befinden sich nicht auf demselben Server.

ToDayIsNow
quelle
4
Welche Art von Benachrichtigung benötigen Sie? Sofortig? Benötigen Sie eine App, um benachrichtigt zu werden, oder benötigen Sie eine E-Mail an Sie? Müssen Sie wirklich benachrichtigt werden oder möchten Sie diese Änderungen nur verfolgen?
Richard
7
Vielleicht möchten Sie das nächste Mal bleiben, nachdem Sie eine Frage gestellt haben, damit Sie Klarstellungen vornehmen / mit den Antwortenden interagieren können. SO Benutzer sind schnell mit Antworten böse, und Sie verpassen eine gute Gelegenheit, gute Antworten zu erhalten, wenn Sie nicht über Ihrer Frage "schweben" und auf Antworten warten.
Richard
Ich muss nur wissen, ob eine andere App Daten aktualisiert oder einfügt. Ich brauche die Daten selbst nicht, nur ein Flag, dass diese Tabelle neue Änderungen enthält. Entschuldigung für die Verspätung Ich wusste nicht, dass die Antworten so schnell sind
ToDayIsNow

Antworten:

55

Sie können die verwenden SqlDependency Class. Die beabsichtigte Verwendung ist hauptsächlich für ASP.NET-Seiten (geringe Anzahl von Client-Benachrichtigungen).

ALTER DATABASE UrDb SET ENABLE_BROKER

Implementieren Sie das OnChangeEreignis, um benachrichtigt zu werden:

void OnChange(object sender, SqlNotificationEventArgs e)

Und im Code:

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

SqlDependency dependency = new SqlDependency(cmd);

dependency.OnChange += OnChange;

Es verwendet die Service Broker(eine nachrichtenbasierte Kommunikationsplattform), um Nachrichten vom Datenbankmodul zu empfangen.

Jaroslav Jandek
quelle
@ jaroslav jandek, Hi. Kennen Sie einen anderen Weg als sqldependency? Ich habe ein Problem mit sqldependency, da es viele Einschränkungen gibt, wie z. B. OUTER JOIN; was ich in fast allen meinen SQL-Abfragen verwende!
M_Mogharrabi
@M_Mogharrabi Die Benachrichtigungen werden mithilfe der Indizierung erstellt, die nicht mit äußeren Verknüpfungen verwendet werden kann. Sie müssten Ihre Verknüpfungen manuell mit äußeren Verknüpfungen als separate Abfragen durchführen. Ich würde versuchen, dies in den meisten Fällen zu vermeiden.
Jaroslav Jandek
2
@Kiquenet Leistung von SB ist hier kein Problem. Die Abfragebenachrichtigungen können jedoch erhebliche Auswirkungen auf die DB-Leistung haben. Besonders wenn es viele Benachrichtigungen gibt (in meiner Antwort erwähnt). Wenn das der Fall ist, sind Sie vielleicht besser dran mit Umfragen, SOA, ...
Jaroslav Jandek
Ich habe gebrauchten SqlSependency zu Trigger - Datenbankänderungen Push - Benachrichtigungen an Kunden zeigen aber vor kurzem zogen wir in SQL Azure und es funktioniert nicht unterstützt SqlSependencyso Gibt es einen besseren Weg , als diese Benachrichtigungen zu erhalten , wenn SQL Azure Datenänderungen oder wenn neue Daten eingefügt werden?
Shaijut
1
@stom gibt es keinen Ersatz, AFAIK. Wenn Sie die Dateneingabe steuern, können Sie einfach mit SignalR oder ähnlichen Technologien benachrichtigen ...
Jaroslav Jandek
45

Der Vollständigkeit halber gibt es einige andere Lösungen, die (meiner Meinung nach) orthodoxer sind als Lösungen, die auf den Klassen SqlDependency (und SqlTableDependency) basieren. SqlDependency wurde ursprünglich entwickelt, um das Aktualisieren verteilter Webserver-Caches zu vereinfachen, und wurde daher an andere Anforderungen angepasst, als wenn es als Event-Produzent konzipiert wäre.

Es gibt im Großen und Ganzen vier Optionen, von denen einige hier noch nicht behandelt wurden:

  • Tracking ändern
  • CDC
  • Löst Warteschlangen aus
  • CLR

Tracking ändern

Quelle: https://docs.microsoft.com/en-us/sql/relational-databases/track-changes/about-change-tracking-sql-server

Änderungsverfolgung ist ein einfacher Benachrichtigungsmechanismus in SQL Server. Grundsätzlich wird bei jeder Änderung an Daten eine datenbankweite Versionsnummer erhöht. Die Versionsnummer wird dann mit einer Bitmaske einschließlich der Namen der geänderten Spalten in die Änderungsverfolgungstabellen geschrieben. Beachten Sie, dass die tatsächliche Änderung nicht beibehalten wird. Die Benachrichtigung enthält nur die Informationen, die eine bestimmte Datenentität geändert hat. Da die Versionierung der Änderungstabelle kumulativ ist, werden Änderungsbenachrichtigungen für einzelne Elemente nicht beibehalten und durch neuere Benachrichtigungen überschrieben. Dies bedeutet, dass bei einer zweimaligen Änderung einer Entität die Änderungsverfolgung nur über die letzte Änderung informiert ist.

Um diese Änderungen in c # zu erfassen, muss Polling verwendet werden. Die Änderungsverfolgungstabellen können abgefragt und jede Änderung überprüft werden, um festzustellen, ob sie von Interesse ist. Wenn es von Interesse ist, müssen Sie direkt zu den Daten gehen, um den aktuellen Status abzurufen.

Datenerfassung ändern

Quelle: https://technet.microsoft.com/en-us/library/bb522489(v=sql.105).aspx

Die Änderungsdatenerfassung (CDC) ist leistungsfähiger, aber am kostspieligsten als die Änderungsverfolgung. Die Änderungsdatenerfassung verfolgt und benachrichtigt Änderungen basierend auf der Überwachung des Datenbankprotokolls. Aus diesem Grund hat CDC Zugriff auf die tatsächlich geänderten Daten und zeichnet alle einzelnen Änderungen auf.

Ähnlich wie bei der Änderungsverfolgung muss die Abfrage verwendet werden, um diese Änderungen in c # zu erfassen. Im Fall von CDC enthalten die abgefragten Informationen jedoch die Änderungsdetails, sodass es nicht unbedingt erforderlich ist, zu den Daten selbst zurückzukehren.

Löst Warteschlangen aus

Quelle: https://code.msdn.microsoft.com/Service-Broker-Message-e81c4316

Diese Technik hängt von den Triggern in den Tabellen ab, für die Benachrichtigungen erforderlich sind. Bei jeder Änderung wird ein Trigger ausgelöst, und der Trigger schreibt diese Informationen in eine Service Broker-Warteschlange. Die Warteschlange kann dann über C # mithilfe des Service Broker-Nachrichtenprozessors verbunden werden (Beispiel im obigen Link).

Im Gegensatz zu Change Tracking oder CDC sind Trigger für Warteschlangen nicht auf Abfragen angewiesen und bieten somit Echtzeit-Eventing.

CLR

Dies ist eine Technik, die ich gesehen habe, aber ich würde sie nicht empfehlen. Jede Lösung, die sich bei der externen Kommunikation auf die CLR stützt, ist bestenfalls ein Hack. Die CLR wurde entwickelt, um das Schreiben von komplexem Datenverarbeitungscode durch die Nutzung von C # zu vereinfachen. Es wurde nicht entwickelt, um externe Abhängigkeiten wie Messaging-Bibliotheken zu verkabeln. Darüber hinaus können CLR-gebundene Vorgänge in Clusterumgebungen auf unvorhersehbare Weise unterbrochen werden.

Das Einrichten ist jedoch recht einfach, da Sie lediglich die Messaging-Assembly bei CLR registrieren müssen und dann mithilfe von Triggern oder SQL-Jobs abrufen können.

Zusammenfassend...

Es hat mich immer wieder überrascht, dass Microsoft sich standhaft geweigert hat, diesen Problembereich anzusprechen. Das Ereignis von der Datenbank zum Code sollte eine integrierte Funktion des Datenbankprodukts sein. In Anbetracht der Tatsache, dass Oracle Advanced Queuing in Kombination mit dem Ereignis ODP.net MessageAvailable vor mehr als 10 Jahren ein zuverlässiges Datenbankereignis für C # bereitstellte, ist dies für MS bedauerlich.

Das Ergebnis ist, dass keine der für diese Frage aufgeführten Lösungen sehr nett ist. Sie alle haben technische Nachteile und erhebliche Einrichtungskosten. Microsoft, wenn Sie zuhören, klären Sie bitte diesen traurigen Zustand.

Tom Redfern
quelle
17

Im Allgemeinen würden Sie Service Broker verwenden

Das ist Trigger -> Warteschlange -> Anwendung (en)

Bearbeiten, nachdem Sie andere Antworten gesehen haben:

Zu Ihrer Information: "Query Notifications" basiert auf dem Service Broker

Edit2:

Weitere Links

gbn
quelle
Ich habe gebrauchten SqlSependency zu Trigger - Datenbankänderungen Push - Benachrichtigungen an Kunden zeigen aber vor kurzem zogen wir in SQL Azure und es funktioniert nicht unterstützt SqlSependencyso Gibt es einen besseren Weg , als diese Benachrichtigungen zu erhalten , wenn SQL Azure Datenänderungen oder wenn neue Daten eingefügt werden?
Shaijut
8

Verwenden Sie SqlTableDependency. Es handelt sich um Ereignisse, die eine Komponente auslösen, wenn ein Datensatz geändert wird. Weitere Details finden Sie unter: https://github.com/christiandelbianco/monitor-table-change-with-sqltabledependency

Es ähnelt .NET SqlDependency, außer dass SqlTableDependency Ereignisse auslöst, die geänderte / gelöschte oder aktualisierte Datenbanktabellenwerte enthalten:

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);
    }
}
Christian Del Bianco
quelle
7

Seien Sie vorsichtig mit der SqlDependency- Klasse - sie hat Probleme mit Speicherlecks.

Verwenden Sie einfach eine plattformübergreifende, .NET 3.5-, .NET Core-kompatible und Open Source-Lösung - SqlDependencyEx . Sie können Benachrichtigungen sowie geänderte Daten erhalten (Sie können über Eigenschaften im Benachrichtigungsereignisobjekt darauf zugreifen). Sie können die Operationen DELETE \ UPDATE \ INSERT auch einzeln oder zusammen ausführen.

Hier ist ein Beispiel dafür, wie einfach es ist, SqlDependencyEx zu verwenden :

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);

Bitte folgen Sie den Links für Details. Diese Komponente wurde in vielen Anwendungen auf Unternehmensebene getestet und hat sich als zuverlässig erwiesen. Hoffe das hilft.

dyatchenko
quelle
2
Ist es mit Sql Express kompatibel?
Dmigo
Sicher, es ist kompatibel
dyatchenko
6

SqlDependency überwacht nicht die Datenbank, sondern den von Ihnen angegebenen SqlCommand. Wenn Sie also versuchen, beispielsweise Werte in die Datenbank in einem Projekt einzufügen und dieses Ereignis in einem anderen Projekt zu erfassen, funktioniert dies nicht, da das Ereignis vom SqlCommand aus stammt 1º-Projekt nicht die Datenbank, da beim Erstellen einer SqlDependency diese mit einem SqlCommand verknüpft wird und nur bei Verwendung dieses Befehls aus diesem Projekt ein Änderungsereignis erstellt wird.

Die Reptilienarmee
quelle
4
Das ist eigentlich nicht richtig. SqlDependency funktioniert auch, wenn Sie Werte in Management Studio einfügen. Diese Klasse hat jedoch viele Probleme wie Speicherlecks. Siehe meine Antwort unten für Details. @ KayLee
dyatchenko
@dyatchenko, danke für deine Meinung. Ich verwende SqlTableDependency, die in einer Antwort dieses Beitrags erwähnt wurde. Ich bin jetzt so beschäftigt, werde aber später einen Blick auf das Speicherproblem werfen ...
Kay Lee
2

sieht den ganzen Weg nach schlechter Architektur aus. Außerdem haben Sie nicht angegeben, bei welchem ​​App-Typ Sie benachrichtigen müssen (Web-App / Konsolen-App / Winforms / Service usw. usw.).

Um Ihre Frage zu beantworten, gibt es jedoch mehrere Möglichkeiten, dies zu lösen. Du könntest benutzen:

1) Zeitstempel, wenn Sie nur daran interessiert waren, sicherzustellen, dass die nächsten Updates aus der zweiten App nicht mit den Updates aus der ersten App in Konflikt stehen

2) SQL-Abhängigkeitsobjekt - Weitere Informationen finden Sie unter http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx

3) Ein benutzerdefinierter Push-Benachrichtigungsdienst, den mehrere Clients (Web / Winform / Service) abonnieren und über Änderungen benachrichtigt werden können

Kurz gesagt, Sie müssen die einfachste und einfachste und kostengünstigste (in Bezug auf den Aufwand) Lösung verwenden, basierend darauf, wie komplex Ihre Benachrichtigungsanforderungen sind und für welchen Zweck Sie sie verwenden müssen. Versuchen Sie nicht, ein übermäßig komplexes Benachrichtigungssystem aufzubauen, wenn eine einfache Datenparallelität Ihre einzige Anforderung ist (in diesem Fall entscheiden Sie sich für eine einfache zeitstempelbasierte Lösung).

Raj
quelle
19
Können Sie aus Neugier klären, was hier "schlechte Architektur" ist?
James
1

Eine andere, sehr einfache Möglichkeit zur Überwachung von Tabellen ist die Tabellenversionierung. Das System funktioniert nachweislich in Konstruktionen wie der DNS-Synchronisation. Damit dies funktioniert, erstellen Sie eine Tabelle mit Tabellennamen und Tabellenversionen als decimaloderbigint.Erstellen Sie in jeder Tabelle, die überwacht werden muss, einen Auslöser beim Einfügen, Aktualisieren und Löschen, der bei Ausführung die entsprechende Tabellenversion in der Versionierungstabelle erhöht. Wenn Sie erwarten, dass eine der überwachten Tabellen häufig geändert wird, müssen Sie die Wiederverwendung der Version vorsehen. Schließlich fragen Sie in Ihrer Anwendung jedes Mal, wenn Sie eine überwachte Tabelle abfragen, auch deren Version ab und speichern sie. Wenn Sie die überwachte Tabelle in Ihrer App ändern, fragen Sie zuerst die aktuelle Version ab und verarbeiten die Änderung nur, wenn die Version unverändert ist. Sie können proc auf einem SQL Server gespeichert haben, um diese Arbeit für Sie zu erledigen. Dies ist eine extrem einfache, aber bewährte feste Lösung.

ArtK
quelle
Ich denke, dies wird einen Sperrengpass in der Zeile erzeugen, die die Version für eine bestimmte Tabelle enthält.
Dan Def
0

Dies ist nicht gerade eine Benachrichtigung, aber im Titel sagen Sie "Monitor" und dies kann zu diesem Szenario passen.

Mithilfe der SQL Server-Zeitstempelspalte können Sie Änderungen (die noch bestehen) zwischen Abfragen leicht erkennen.

Der SQL Server-Zeitstempel-Spaltentyp ist meiner Meinung nach schlecht benannt, da er überhaupt nicht mit der Zeit zusammenhängt. Es handelt sich um einen datenbankweiten Wert, der bei jeder Einfügung oder Aktualisierung automatisch erhöht wird. Sie können Max (Zeitstempel) in einer Tabelle auswählen, nach der Sie suchen, oder den Zeitstempel aus der gerade eingefügten Zeile zurückgeben und dann einfach auswählen, wo Zeitstempel> gespeicherter Zeitstempel angezeigt wird. Dadurch erhalten Sie alle Ergebnisse, die zwischen diesen Zeiten aktualisiert oder eingefügt wurden.

Da es sich auch um einen datenbankweiten Wert handelt, können Sie mit Ihrem gespeicherten Zeitstempel überprüfen, ob in eine Tabelle Daten geschrieben wurden, seit Sie Ihren gespeicherten Zeitstempel zuletzt überprüft / aktualisiert haben.

Matt
quelle