更好的缓存.NET 3.5站点

时间:2013-12-27 12:32:34

标签: c# .net-3.5 asp.net-3.5

我正在尝试优化旧应用程序,现在我正在尝试将SQL请求降至最低。 我已经创建了简单的缓存机制,但它需要3种方法:

public static List<Models.CarModel> GetCarModels()
{
    return GetCarModels(false);
}

public static List<Models.CarModel> GetCarModels(bool reload)
{
    const string my_key = "GetCarModels";
    object list = HttpContext.Current.Cache[my_key] as List<Models.CarModel>;
    if ((reload) || (list == null))
    {
        list = GetCarModels_P();
        HttpContext.Current.Cache.Insert(my_key, list, null, DateTime.Now.AddHours(1), TimeSpan.Zero);
    }
    return (List<Models.CarModel>)list;
}

private static List<Models.CarModel> GetCarModels_P()
{
    var tmp_list = new List<Models.CarModel>();

    using (var conn = new SqlConnection())
    {
        conn.ConnectionString = ConfigurationManager.ConnectionStrings["HelpDesk"].ToString();
        using (var cmd = new SqlCommand(@"SELECT_CAR_MODELS", conn))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.CommandTimeout = 360;
            conn.Open();
            using (SqlDataReader sdr = cmd.ExecuteReader())
            {
                while (sdr.Read())
                {
                    var carModel = new Models.CarModel()
                    {
                        Id = Convert.ToInt32(sdr["Id"]),
                        Name= Convert.ToString(sdr["CarName"])
                    };
                    tmp_list.Add(carModel );
                }
            }
            conn.Close();
        }
    }
    return tmp_list;
}

这很好用,sql查询结果缓存了1个小时,但是对于每个旧方法我必须创建3个新的,所以对于10个旧方法我必须写30个新的。
我想减少必须编写的代码数量,可能有一种方法可以创建读取/写入缓存的通用方法。

GetCarModels_P可能不会改变,但我可以优化我的两种公共方法(I quess)。

3 个答案:

答案 0 :(得分:1)

您可以使用泛型和lambda来简化您的更改:

public static List<T> GetViaCache<T>(bool reload, string key, Func<List<T>> loader)
{
    object list = HttpContext.Current.Cache[key] as List<T>;
    if ((reload) || (list == null))
    {
        list = loader();
        HttpContext.Current.Cache.Insert(key, list, null, DateTime.Now.AddHours(1), TimeSpan.Zero);
    }
    return list;
}

这将加载代码简化为

public static List<Models.CarModel> GetCarModels(bool reload)
{
    return GetViaCache<Models.CarModel>(reload, "GetCarModels", GetCarModels_P);
}

当然,您仍然需要为缓存生成唯一的密钥。

答案 1 :(得分:1)

您可以在辅助类中实现该模式,如下所示:

internal class Cached<T> where T: class
{
    private readonly Func<T> _loadFunc;
    private readonly string _key;
    private readonly TimeSpan _expiration;

    public Cached(Func<T> loadFunc, string key, TimeSpan expiration)
    {
        _loadFunc = loadFunc;
        _key = key;
        _expiration = expiration;
    }

    public T GetValue(bool reload)
    {
        T value = (T)HttpContext.Current.Cache[_key];

        if (reload || value == null)
        {
            value = _loadFunc();
            HttpContext.Current.Cache.Insert(_key, value, null,
                DateTime.Now + _expiration, TimeSpan.Zero);
        }

        return value;
    }
}

你会这样使用它:

private static Cached<List<Models.CarModel>> _carModels =
      new Cached<List<Models.CarModel>>(
          GetCarModels_P, "GetCarModels", TimeSpan.FromHours(1));

public static List<Models.CarModel> GetCarModels()
{
    return _carModels.GetValue(false);
}

当然,您也可以只使用通用方法(就像我写这篇文章时发布的其他答案之一)。这取决于我将使用的情况。如果你有类似的强制重新加载的调用,我的方法会更容易,因为你不必重复自己。但是,在不利方面,我的实现有点暗示Cached实例本身保留了数据,而实际上是HttpContext缓存这样做。

答案 2 :(得分:0)

您刚刚写了两个非常好的理由,说明为什么要使用像NHibernate或Entity Framework这样的ORM层。他们带走了痛苦,编写了大量的样板SQL调用函数。他们支持缓存,我知道这很简单,就像NH一样,不确定EF。

不需要丢弃任何现有代码,ORM可以与您现有的数据库代码共存,甚至可以使用完全相同的连接。您可以逐个迁移现有功能,从无法使用的SQL迁移到您选择的ORM。如果您想花时间优化旧应用,我会说这是花时间的最佳方式。