在字典中缓存通用数据

时间:2015-12-10 14:42:40

标签: c# generics caching dictionary

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

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(); });
        }

我必须修改每个缓存类。我需要声明变量,将它添加到try-catch块,然后在块中插入6个类中的相同行。这段代码对我来说似乎很模糊,我无法相信没有更简单的解决方案。我尝试使用AddItem,LoadData,OnLoadDataFailed方法创建一个接口,但是在AddItem方法中我需要指定项目,我被卡住了。

1 个答案:

答案 0 :(得分:0)

这是使用Generics想要完成的(我认为)的基本结构。

首先,声明缓存项的公共接口,以便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");