public override (IReadOnlyCollection <Row>, IReadOnlyCollection <Row>, IReadOnlyCollection <Row>) CalculateChanges()
        {
            List <Row> inserted = new List <Row>();
            List <Row> updated  = new List <Row>();
            List <Row> deleted  = new List <Row>();

            Db.Config.DatabaseConnectionString.WithReader(Query, reader =>
            {
                Dictionary <object[], Row> oldState = new Dictionary <object[], Row>(_data, Schema.RowKeyEqualityComparer);
                while (reader.Read())
                {
                    var row = Schema.ReadRow(reader);
                    if (_data.TryGetValue(row.Key, out Row oldRow))
                    {
                        oldState.Remove(row.Key);
                        if (Schema.RowEqualityComparer.Equals(row, oldRow) == false)
                        {
                            updated.Add(row);
                            _data[row.Key] = row;
                        }
                    }
                    else
                    {
                        inserted.Add(row);
                        _data.Add(row.Key, row);
                    }
                }

                deleted = oldState.Values.ToList();
                _data.RemoveAll(oldState.Keys);
            });
            return(inserted, updated, deleted);
        }
        private void ViewOnInvalidated()
        {
            var changes = _view.CalculateChanges();

            lock (_dataAccessLock)
            {
                foreach (var row in changes.Item1)
                {
                    var entry = _rowFactory(row);
                    var key   = _keyExtractor(entry);
                    _rows.Add(key, entry);
                }
                foreach (var row in changes.Item2)
                {
                    var entry = _rowFactory(row);
                    var key   = _keyExtractor(entry);
                    _rows[key] = entry;
                }

                _rows.RemoveAll(changes.Item3.Select(_rowFactory).Select(_keyExtractor));
            }
        }