通过相等性缓存LINQ表达式

6
考虑以下情况。
您有一个允许进行某些调用的存储库。这些调用使用LINQ并且在返回的数据量方面可能相对昂贵。
考虑到我的情况,如果数据过时也不会太糟糕 - 可以实现缓存,以便不必每次调用都执行大型和昂贵的查询。嘿,我们甚至可以实现一些缓存策略,根据时间或使用情况确定何时再次执行该查询。
我试图理解的问题是如何在缓存中对其进行键入。一种方法是简单地说:
"querytype1" = Particular LINQ expression
"querytype2" = Particular LINQ expression

然后,通过一个简单的字符串来缓存密钥。但是,考虑到我们正在使用LINQ,我们是否可以用LINQ表达式本身作为缓存密钥呢?我明白这可能会影响性能,但有没有办法比较两个LINQ表达式是否相同?


你会如何比较LINQ表达式?这个对象是否实现了IComparable接口? - Kyle C
@KyleC 这是我的问题。是否有可能找出两个LINQ表达式在语义上是否相同(与结果集无关)? - Moo-Juice
你可能想看一下Lazy<T>类和模式:http://msdn.microsoft.com/zh-cn/library/dd642331.aspx - Dan Esparza
2个回答

1
这是我目前的解决方案。
考虑到在代码库中,我们将会有类似以下的调用:
public IEnumerable<MYPOCO> GetData(string someParameter, int anotherParameter);

因此,我们可以说这些参数是“标准”。因此,我引入了一个“Criteria”类,它基本上包含了一个“Dictionary<string, object>”实例,并且有一些类型安全的设置器和获取器,简化如下:
public class Criteria
{
    private Dictionary<string, object> _criteria = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);

    public Criteria Set<T>(string key, T value)
    {
        _criteria[key] = value;
        return this;
    } // eo Set

    public T Get<T>(string key)
    {
        return _criteria.ContainsKey(key) ? _criteria[key] : default(T);
    } // eo Get

    public Dictionary<string, object> Items { get { return _criteria; } }
}    // eo class Criteria

然后,我根据这个Stackoverflow答案Dictionary<TK, TV>编写了一个扩展方法。最后,我编写了一个与Criteria类型一起使用的IEqualityComparer<Criteria>类。
这意味着我的缓存现在以标准为键,该标准是使用传递给存储库的参数设置的。
public class MyPocoRepository<TMYPOCO>
{
    private Cache<Criteria, IEnumerable<TMYPOCO>> _cache = new Cache<Criteria, IEnumerable<TMYPOCO>>(CriteriaComparer); // is passed to the dictionary constructor which is actually the cache.
    public IEnumerable<TMYPOCO> GetData(string someParameter, int anotherParameter)
    {
        Criteria criteria = new Criteria();
        criteria.Set("someParameter", someParameter)
                .Set("anotherParameter", anotherParameter);
        // we can check the cache now based on this...
    } // eo GetData
} // eo MyPocoRepository<TMYPOCO>

请注意,这也使我能够在需要缓存策略时扩展此想法,其中参数完全相同,但可能是不同的用户帐户正在访问它(我们可以添加一个字段,例如 - 用户类型,到标准中,即使LINQ表达式不会使用它)。

如果您想将实例作为键存储在 Dictionary<Criteria,whatever> 中,则需要重写 EqualsGetHashCode - Charles Lambert
@CharlesLambert,这会教训我,写帖子时没有代码在我面前。请查看编辑,它是IEqualityComparer<> - Moo-Juice

1

如果你看过我对其他问题的许多回答,当我问及性能影响时,你会感到惊讶。唉,我们所谈论的数据集可能非常大,而SELECT语句本身将是巨大的(遗憾的是,这会从多个第三方解决方案中提取内容,因此我无法真正缩小查询)。这可能会使关键字处于“1kb+”比较范围内。但实际上,这比重新查询要便宜得多(数量级)。我想知道是否可以哈希一个LINQ表达式。 - Moo-Juice
你可以对键进行哈希并查找冲突。 - Joey Gennari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接