I have an application that gets the user's actions, I subscribed the DB table user_actions (table columns: id [PK], action [int], date_created [datetime]) to SQL dependency. my problem is when I inserted 2 rows at the same time example: action=2 and action=3 then insert another 15 rows of action=2. The row for action=3 skipped sometimes action=2 as well.
From my app it shows like:
id: 1, action: 2
id: 2, action: 3 --- missing
id: 3, action: 2
id: 4, action: 2
id: 5, action: 2
id: 6, action: 2
id: 7, action: 2
id: 8, action: 2 --- missing
id: 9, action: 2
id: 10, action: 2
id: 11, action: 2
id: 12, action: 2 --- missing
id: 13, action: 2
Does anyone experience the same thing as mine? what is the possible problem?
Kind regards.
Here is my code:
void Initialization()
{
// Create a dependency connection.
SqlDependency.Stop(connectionString);
SqlDependency.Start(connectionString);
SqlDependencyInit();
}
void SqlDependencyInit()
{
using (var conn = new SqlConnection(connectionString))
{
conn.Open();
// Create a new SqlCommand object.
using (SqlCommand command = conn.CreateCommand())
{
command.CommandType = "Text";
command.CommandText = "SELECT id FROM dbo.user_actions";
command.Notification = null;
// Create a dependency and associate it with the SqlCommand.
SqlDependency dependency = SqlDependency(command);
// Subscribe to the SqlDependency event.
dependency.OnChange+=new
OnChangeEventHandler(OnDependencyChange);
// Execute the command.
command.ExecuteReader();
}
}
}
void OnDependencyChange(object sender,SqlNotificationEventArgs e)
{
if (e.Info == SqlNotificationInfo.Insert)
{
var id = Helper.ExecuteScalar("select top 1 id from user_actions order by id desc");
processUserAction(id);
SqlDependencyInit();
}
}
The answer is quite simple: the event gets fired once per modification statement, not once per row. If you want to process only new rows, you need some way of tracking them. The easiest, if rather unreliable, method is to keep track of the last ID seen.
You are also resubscribing the event each time the event is called. You shouldn't need to do this, you only need to catch errors in order to resubscribe.
A better solution might be to create a
rowversioncolumn on the table, and then keep track of that. This is guaranteed to increment monotonically for every change. You can pass it like this