web-dev-qa-db-fra.com

Comment surveiller les changements de table SQL Server en utilisant c #?

J'ai plusieurs applications accédant à la même base de données et je dois recevoir une notification si l'une de ces applications modifie quelque chose (mise à jour, insertion) dans une certaine table.

La base de données et les applications ne sont pas sur le même serveur.

61
ToDayIsNow

Vous pouvez utiliser le SqlDependency Class . Son utilisation prévue concerne principalement les pages ASP.NET (nombre réduit de notifications client).

ALTER DATABASE UrDb SET ENABLE_BROKER

Implémentez l'événement OnChange pour être averti:

void OnChange(object sender, SqlNotificationEventArgs e)

Et en code:

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

SqlDependency dependency = new SqlDependency(cmd);

dependency.OnChange += OnChange;

Il utilise le Service Broker (plate-forme de communication à base de messages) pour recevoir des messages du moteur de base de données.

51
Jaroslav Jandek

Dans un souci de complétude, il existe deux autres solutions qui, à mon avis, sont plus orthodoxes et bien établies que les solutions reposant sur les classes SqlDependency (et SqlTableDependency). SqlDependency a été conçu pour actualiser le cache du serveur Web et ne fournit donc pas le type de résilience au chargement que vous auriez besoin d’un producteur d’événements.

Il y a en gros quatre autres options non mentionnées ici:

  • Suivi du changement
  • CDC
  • Déclencheurs de files d'attente
  • CLR

Suivi des modifications

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

Le suivi des modifications est un mécanisme de notification léger dans SQL Server. Fondamentalement, un numéro de version à l'échelle de la base de données est incrémenté à chaque modification des données. Le numéro de version est ensuite écrit dans les tables de suivi des modifications avec un masque binaire incluant les noms des colonnes modifiées. Notez que la modification réelle n'est pas conservée. La notification contient uniquement les informations selon lesquelles une entité de données particulière a été modifiée. De plus, étant donné que le contrôle des versions de la table de modifications est cumulatif, les notifications de modification sur des éléments individuels ne sont pas conservées et sont remplacées par des notifications plus récentes. Cela signifie que si une entité change deux fois, le suivi des modifications ne sera informé que des modifications les plus récentes.

Afin de capturer ces changements dans c #, la scrutation doit être utilisée. Les tables de suivi des modifications peuvent être interrogées et chaque modification inspectée pour déterminer si elle présente un intérêt. S'il y a un intérêt, il est alors nécessaire d'aller directement aux données pour récupérer l'état actuel.

Modification de la capture de données

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

La capture de données de changement (CDC) est plus puissante mais plus coûteuse que le suivi des modifications. La capture de données de modification suivra et notifiera les modifications en fonction de la surveillance du journal de base de données. De ce fait, le CDC a accès aux données réelles qui ont été modifiées et conserve un enregistrement de toutes les modifications individuelles.

De même, pour suivre le changement, afin de capturer ces changements dans c #, la scrutation doit être utilisée. Toutefois, dans le cas de CDC, les informations interrogées contiendront les détails de la modification. Il n'est donc pas absolument nécessaire de revenir aux données elles-mêmes.

Déclenche les files d'attente

Source: https://code.msdn.Microsoft.com/Service-Broker-Message-e81c4316

Cette technique dépend des déclencheurs sur les tables à partir desquelles des notifications sont requises. Chaque modification déclenche un déclencheur qui écrira ces informations dans une file d'attente de service broker. La file d'attente peut ensuite être connectée via C # à l'aide du processeur de messages Service Broker (exemple dans le lien ci-dessus).

Contrairement au suivi des modifications ou au CDC, les déclencheurs de files d'attente ne reposent pas sur une interrogation et fournissent par conséquent des événements en temps réel.

[~ # ~] clr [~ # ~]

C’est une technique que j’ai vue utilisée, mais je ne la recommanderais pas. Toute solution qui repose sur le CLR pour communiquer en externe est au mieux un hack. Le CLR a été conçu pour faciliter l’écriture de code de traitement de données complexe en utilisant C #. Il n'a pas été conçu pour être connecté à des dépendances externes telles que des bibliothèques de messagerie. De plus, les opérations liées au CLR peuvent se rompre dans les environnements en cluster de manière imprévisible.

Cela dit, la configuration est assez simple, il vous suffit d’enregistrer l’assembly de messagerie avec CLR pour pouvoir ensuite appeler à l’aide de déclencheurs ou de travaux SQL.

En résumé ...

Cela a toujours été une source d’étonnement pour moi que Microsoft refuse fermement de traiter cet espace problématique. L'événement de la base de données au code doit être une fonctionnalité intégrée du produit de base de données. Considérant que Oracle Advanced Queuing combiné à l'événement ODP.net MessageAvailable fournissait une base de données fiable à C # plus que il y a 10 ans, c'est dommage de la part de MS.

Le résultat de cela est qu'aucune des solutions énumérées à cette question n'est très gentille. Ils présentent tous des inconvénients techniques et ont un coût d'installation important. Microsoft, si vous écoutez, veuillez régler ce triste état de choses.

30
tom redfern

Généralement, vous utiliseriez Service Broker

C'est déclencheur -> file d'attente -> application (s)

Modifier, après avoir vu d'autres réponses:

FYI: "Notifications de requête" est construit sur Service broker

Edit2:

Plus de liens

17
gbn

Utilisez SqlTableDependency. C'est un composant c # qui déclenche des événements lorsqu'un enregistrement est modifié. Vous pouvez trouver d'autres détails sur: https://github.com/christiandelbianco/monitor-table-change-with-sqltabledependency

Il est similaire à .NET SqlDependency sauf que SqlTableDependency déclenche des événements contenant des valeurs de table de base de données modifiées/supprimées ou mises à jour:

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

Soyez prudent en utilisant SqlDependency class - il a problèmes avec des fuites de mémoire.

Utilisez simplement une solution multi-plateforme, .NET 3.5, compatible .NET Core et open source - SqlDependencyEx . Vous pouvez obtenir des notifications ainsi que des données modifiées (vous pouvez y accéder via les propriétés de l'objet d'événement de notification). Vous pouvez également utiliser les opérations DELETE\UPDATE\INSERT séparément ou ensemble.

Voici un exemple de la facilité d'utilisation 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);

Veuillez suivre les liens pour plus de détails. Ce composant a été testé dans de nombreuses applications d'entreprise et s'est révélé fiable. J'espère que cela t'aides.

6
dyatchenko

SqlDependency ne surveille pas la base de données mais surveille la SqlCommand que vous spécifiez. Par conséquent, si vous essayez d'insérer des valeurs dans la base de données d'un projet et de capturer cet événement dans un autre projet, cela ne fonctionnera pas car l'événement provenait de la SqlCommand 1º projet pas la base de données parce que lorsque vous créez un SqlDependency vous le liez à un SqlCommand et c’est seulement lorsque cette commande de ce projet est utilisée qu'elle crée un événement Change.

6
The Reptilian Army

Depuis SQL Server 2005, vous avez la possibilité d’utiliser Query Notifications , qui peut être exploité par ADO.NET. Voir http://msdn.Microsoft.com/en-us/library/t9x04ed2 .aspx

4
Chris Taylor

ressemble à une mauvaise architecture tout le chemin. De plus, vous n'avez pas spécifié le type d'application que vous devez notifier (application web/console app/winforms/service, etc.).

néanmoins, pour répondre à votre question, il existe plusieurs façons de résoudre ce problème. vous pouvez utiliser:

1) les horodatages si vous souhaitez simplement vous assurer que les prochaines mises à jour de la deuxième application ne sont pas en conflit avec les mises à jour de la première application

2) Objet de dépendance sql - voir http://msdn.Microsoft.com/en-us/library/system.data.sqlclient.sqldependency.aspx pour plus d'informations.

3) un service de notification Push personnalisé auquel plusieurs clients (Web/winform/service) peuvent s'abonner et être avertis des modifications

en bref, vous devez utiliser la solution la plus simple, la plus simple et la moins chère (en termes d'effort) basée sur la complexité de vos exigences en matière de notification et sur les objectifs pour lesquels vous souhaitez les utiliser. N'essayez pas de créer un système de notification trop complexe si une simple concurrence de données est votre seule exigence (dans ce cas, optez pour une solution simple basée sur un horodatage).

2
Raj

Un autre moyen très simple de surveiller les tables est la gestion des versions. Le système a fait ses preuves dans des constructions telles que la synchronisation DNS. Pour que cela fonctionne, vous créez une table contenant des noms de table et des versions de table sous la forme decimal ou bigint.Dans chaque table à surveiller, créez un déclencheur lors de l'insertion, de la mise à jour et de la suppression qui incrémentera la version de la table appropriée dans la table de contrôle de version lors de son exécution. Si vous vous attendez à ce que l'une des tables surveillées soit souvent modifiée, vous devez prévoir la réutilisation de la version. Enfin, dans votre application, chaque fois que vous interrogez une table surveillée, vous interrogez également sa version et la stockez. Lorsque vous modifiez la table surveillée à partir de votre application, vous interrogez d'abord sa version actuelle et ne traitez la modification que si la version est inchangée. Vous pouvez faire en sorte que proc stocké sur un serveur SQL effectue ce travail pour vous. C'est une solution solide extrêmement simple mais éprouvée. Il a une utilisation fonctionnelle spécifique (pour assurer la cohérence des données) et est léger en ressources (vous ne déclenchez pas d'événements sponsorisés que vous ne surveillez pas) mais a besoin d'une application pour vérifier activement les modifications plutôt que d'attendre passivement que l'événement se produise.

1
ArtK