DataCollection | ComponentOne
In This Topic
    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();
                }
            }
        }
    }