Skip to content

Instantly share code, notes, and snippets.

@DamianEdwards
Created March 19, 2013 05:54
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DamianEdwards/5193986 to your computer and use it in GitHub Desktop.
Save DamianEdwards/5193986 to your computer and use it in GitHub Desktop.
Demonstrates that SqlDependency notifications can occur concurrently with the command that set them up. This might cause issues in certain cases if the application isn't expecting multiple commands to be executed at the same time.
using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;
namespace SqlDependencyConcurrency
{
class Program
{
private static readonly string _connectionString = "Data Source=(local);Initial Catalog=Sample;Integrated Security=SSPI;";
static void Main(string[] args)
{
Install();
SqlDependency.Start(_connectionString);
var publisher = new Thread(Publisher);
var consumer = new Thread(Consumer);
publisher.Start(IsolationLevel.ReadCommitted);
consumer.Start(IsolationLevel.ReadCommitted);
Console.ReadLine();
publisher.Abort();
consumer.Abort();
SqlDependency.Stop(_connectionString);
}
private static void Publisher(object arg)
{
var isolationLevel = (IsolationLevel)arg;
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
for (var i = 0; i < 10; i++)
{
using (var transaction = connection.BeginTransaction(isolationLevel))
{
var command = new SqlCommand("INSERT INTO [Sample].[dbo].[S] (Message) VALUES (@Message)", connection);
command.Parameters.AddWithValue("Message", i.ToString());
command.Transaction = transaction;
command.ExecuteNonQuery();
transaction.Commit();
}
Console.WriteLine("+ Publisher: inserted " + i.ToString());
Thread.Sleep(500);
}
Console.WriteLine("+ Publisher: finished inserting");
}
}
private static void Consumer(object arg)
{
var isolationLevel = (IsolationLevel)arg;
// Wait a little so we have some initial rows
Thread.Sleep(1500);
using (var connection = new SqlConnection(_connectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction(isolationLevel))
{
var command = new SqlCommand("SELECT * FROM [Sample].[dbo].[S]", connection);
command.Transaction = transaction;
var dependency = new SqlDependency(command);
dependency.OnChange += SqlDepdendencyOnChange;
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("- Consumer: read row " + reader.GetString(1));
// Wait here long enough so that new rows should be added and trigger the dependency callback
Thread.Sleep(500);
}
}
}
Console.WriteLine("- Consumer: finished reading");
}
}
private static void SqlDepdendencyOnChange(object sender, SqlNotificationEventArgs e)
{
Console.WriteLine("> SqlDependency.OnChange fired!");
// At this point you'd usually go off and make the query again
}
private static void Install()
{
using (var connection = new SqlConnection(_connectionString.Replace("=Sample;", "=master;")))
{
connection.Open();
var command = new SqlCommand(
@"IF NOT EXISTS(SELECT [database_id] FROM [sys].[databases] WHERE [name] = 'Sample')
CREATE DATABASE [Sample];
ALTER DATABASE [Sample] SET ENABLE_BROKER;
Use [Sample];
IF NOT EXISTS(SELECT [object_id] FROM [sys].[tables] WHERE [name] = 'S')
BEGIN
CREATE TABLE [Sample].[dbo].[S] (
[MessageId] [int] IDENTITY(1,1) NOT NULL,
[Message] [nvarchar](256) NOT NULL,
CONSTRAINT [PK_S] PRIMARY KEY CLUSTERED ([MessageId] ASC));
END
ELSE
DELETE FROM [Sample].[dbo].[S];", connection);
command.ExecuteNonQuery();
}
}
}
}
+ Publisher: inserted 0
+ Publisher: inserted 1
+ Publisher: inserted 2
+ Publisher: inserted 3
- Consumer: read row 0
> SqlDependency.OnChange fired!
+ Publisher: inserted 4
- Consumer: read row 1
+ Publisher: inserted 5
- Consumer: read row 2
+ Publisher: inserted 6
- Consumer: read row 3
+ Publisher: inserted 7
- Consumer: finished reading
+ Publisher: inserted 8
+ Publisher: inserted 9
+ Publisher: finished inserting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment