在字典中缓存通用数据

本文关键字:数据 缓存 字典 | 更新日期: 2023-09-27 18:26:22

我有一个应用程序,它在启动时缓存一些数据。有几种东西可以放在缓存中,但它们非常相似。我创建了这样的类,它们之间唯一的区别是要添加到字典中的项的类型(在本例中为Setting类)和_sqlNotifyCommandText.

public class SettingsCache : ILoggerClass
{
    private Dictionary<int, Dictionary<int, Setting>> _cachedItems;
    private string _entityConnectionString;
    private SQLNotifier _sqlNotifier;
    private SqlCommand _sqlNotifyCommand = new SqlCommand();
    private bool _dataLoaded = false;
    private void AddItem(Setting item)
    {
        if (!_cachedItems.ContainsKey(item.PartnerId))
        {
            _cachedItems.Add(item.PartnerId, new Dictionary<int, Setting>());
        }
        if (_cachedItems[item.PartnerId].ContainsKey(item.Id))
        {
            _cachedItems[item.PartnerId].Remove(item.Id);
        }
        _cachedItems[item.PartnerId].Add(item.Id, item);
    }
    public Setting GetSetting(int partnerId, int id)
    {
        if (_cachedItems.ContainsKey(partnerId))
        {
            if (_cachedItems[partnerId].ContainsKey(id))
            {
                return _cachedItems[partnerId][id];
            }
            return null;
        }
        return null;
    }
    public SettingsCache(string connectionString)
    {
        _entityConnectionString = connectionString;
        _cachedItems = new Dictionary<int, Dictionary<int, Setting>>();
        LoadData();
        try
        {
            using (var db = new partnerEntity(connectionString))
            {
                string adoSqlConnectionString = ((EntityConnection) db.Connection).StoreConnection.ConnectionString;
                _sqlNotifier = new SQLNotifier(adoSqlConnectionString);
                _sqlNotifier.NewMessage += _sqlNotifier_NewMessage;

                _sqlNotifyCommand.CommandType = CommandType.Text;
                _sqlNotifyCommand.CommandText = "SELECT setting_id, setting_value, partner_id FROM dbo.setting";
                _sqlNotifyCommand.Notification = null;
                _sqlNotifier.RegisterDependency(_sqlNotifyCommand);
            }
        }
        catch (Exception exception)
        {
            this.Log(this, LogLevel.Error, 0, exception);
        }
    }
    private void _sqlNotifier_NewMessage(object sender, SqlNotificationEventArgs e)
    {
        if (e.Info == SqlNotificationInfo.Insert || e.Info == SqlNotificationInfo.Update)
        {
            this.Log(this, LogLevel.Info, 0, string.Format("Database changed, reloading settings data..."));
            LoadData();
        }
        _sqlNotifier.RegisterDependency(_sqlNotifyCommand);
    }
    private void LoadData()
    {
        _dataLoaded = false;
        try
        {
            using (var db = new partnerEntity(_entityConnectionString))
            {
                var dbData = db.setting.ToList();
                foreach (var cItem in dbData)
                {
                    AddItem(new Setting
                    {
                        PartnerId = cItem.partner_id,
                        Id = cItem.setting_id,
                        Value = cItem.setting_value
                    });
                }
            }
            _dataLoaded = true;
        }
        catch (Exception exception)
        {
            this.Log(this, LogLevel.Error, 0, exception);
        }
        if (!_dataLoaded)
        {
            Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(_ => { LoadData(); });
        }
    }
}

有没有更通用的方法可以做到这一点?这一部分的课程中需要的最后一件事:

            if (!_dataLoaded)
        {
            Task.Delay(TimeSpan.FromSeconds(10)).ContinueWith(_ => { LoadData(); });
        }

我必须修改每个Caching类。我需要声明变量,将其添加到try-catch块中,并在块之后在6个类中插入同一行。这段代码对我来说似乎是样板,我不敢相信没有更简单的解决方案。我试图用AddItem、LoadData、OnLoadDataFailed方法创建一个接口,但在AddItem方法中,我需要指定项,我被卡住了。

在字典中缓存通用数据

以下是您想要使用泛型实现的(我认为)基本结构。

首先,为缓存项声明一个通用接口,以便AddItem方法仍然有效:

public interface ICacheItem
{
    int Id { get; set; }
    int PartnerId { get; set; }
}

现在,您可以创建保存项目的SettingsCache<T>

public class SettingsCache<T> : ILogger where T : ICacheItem
{
    private Dictionary<int, Dictionary<int, T>> _cachedItems;
    //...
    public SettingsCache(string connectionString, string commandText)
    {
        //...
    }
    private void AddItem(T item)
    {
        if (!_cachedItems.ContainsKey(item.PartnerId))
        {
            _cachedItems.Add(item.PartnerId, new Dictionary<int, T>());
        }
        if (_cachedItems[item.PartnerId].ContainsKey(item.Id))
        {
            _cachedItems[item.PartnerId].Remove(item.Id);
        }
        _cachedItems[item.PartnerId].Add(item.Id, item);
    }
}

我省略了大部分实现,重点讨论了您最关心的两个问题,命令文本和AddItem方法。泛型有一个约束,因此它只能接受ICacheItem的项,因此您可以使用ICacheItem定义的任何属性。

要使用缓存,只需创建一个具有特定类型的缓存(假设Setting实现ICacheItem):

var settingsCache = new SettingsCache<Setting>("connection string", "command string");