SQLServerDataCollection.cs
In This Topic
using C1.DataCollection.AdoNet;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Data.Common;
using System.Threading;
using System.Threading.Tasks;
using TableDependency.SqlClient;
using TableDependency.SqlClient.Base.Enums;
using TableDependency.SqlClient.Base.EventArgs;
namespace SQLServerRealTimeUpdates.Data
{
public class SQLServerDataCollection<T> : C1AdoNetCursorDataCollection<T>, IAsyncDisposable
where T : class, new()
{
/// Initializes a new instance of the <see cref="SQLServerDataCollection{T}"/> class.
/// </summary>
/// <param name="connection">The ado.net connection.</param>
/// <param name="tableName">The table name.</param>
/// <param name="comparer">Comparer used to determine the identity of the items.</param>
/// <param name="fields">The fields that will be queried.</param>
public SQLServerDataCollection(DbConnection connection, string tableName, IEqualityComparer<T> comparer = null, IEnumerable<string> fields = null)
: base(connection, tableName, fields)
{
SynchronizationContext = SynchronizationContext.Current;
Comparer = comparer ?? EqualityComparer<T>.Default;
}
private SynchronizationContext? SynchronizationContext { get; }
private IEqualityComparer<T> Comparer { get; }
private SqlTableDependency<T>? Notifier { get; set; }
///<inheritdoc/>
protected override async Task ConnectAsyncOverride(CancellationToken cancellationToken)
{
await base.ConnectAsyncOverride(cancellationToken);
Notifier = new SqlTableDependency<T>(Connection.ConnectionString, TableName);
Notifier.OnChanged += OnTableDependencyChanged;
Notifier.Start();
}
///<inheritdoc/>
protected override async Task DisconnectAsyncOverride(CancellationToken cancellationToken)
{
if (Notifier != null)
{
Notifier.OnChanged -= OnTableDependencyChanged;
Notifier.Stop();
}
await base.DisconnectAsyncOverride(cancellationToken);
}
///<inheritdoc/>
public async ValueTask DisposeAsync()
{
await DisconnectAsync();
}
private void OnTableDependencyChanged(object sender, RecordChangedEventArgs<T> e)
{
RunInContext(o =>
{
switch (e.ChangeType)
{
case ChangeType.Delete:
{
var index = InternalList.FindIndex(o => Comparer.Equals(o, e.Entity));
if (index >= 0)
{
var oldItem = InternalList[index];
InternalList.RemoveAt(index);
OnCollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldItem, index));
}
}
break;
case ChangeType.Insert:
{
InternalList.Add(e.Entity);
OnCollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, e.Entity, InternalList.Count - 1));
}
break;
case ChangeType.Update:
{
var index = InternalList.FindIndex(o => Comparer.Equals(o, e.Entity));
if (index >= 0)
{
var oldItem = InternalList[index];
InternalList[index] = e.Entity;
OnCollectionChanged(sender, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, e.Entity, oldItem, index));
}
}
break;
}
}, e);
}
private void RunInContext(Action<object?> action, object? state)
{
if (SynchronizationContext != null)
SynchronizationContext.Post(new SendOrPostCallback(action), state);
else
action(state);
}
protected override async Task<int> InsertAsyncOverride(int index, T item, CancellationToken cancellationToken)
{
try
{
Notifier?.Stop();
return await base.InsertAsyncOverride(index, item, cancellationToken);
}
finally
{
Notifier?.Start();
}
}
protected override async Task RemoveAsyncOverride(int index, CancellationToken cancellationToken)
{
try
{
Notifier?.Stop();
await base.RemoveAsyncOverride(index, cancellationToken);
}
finally
{
Notifier?.Start();
}
}
protected override async Task ReplaceAsyncOverride(int index, T item, CancellationToken cancellationToken)
{
try
{
Notifier?.Stop();
await base.ReplaceAsyncOverride(index, item, cancellationToken);
}
finally
{
Notifier?.Start();
}
}
}
}