在字典中缓存通用数据
本文关键字:数据 缓存 字典 | 更新日期: 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");