【问题标题】:Caching LINQ expressions by equality通过相等缓存 LINQ 表达式
【发布时间】:2013-04-18 20:12:03
【问题描述】:

考虑这种情况。

您有一个允许对其进行某些调用的存储库。这些调用使用 LINQ,并且在返回的数据量方面可能相对昂贵。

在我的情况下,如果数据是旧的,这并不算太糟糕 - 可以实现缓存,这样就不会在每次调用时都执行大而昂贵的查询。嘿,我们甚至可以实现一些缓存策略,以根据时间或使用情况确定何时再次执行该查询。

我想要解决的问题是如何在缓存中键入它。一种方法是简单地说:

"querytype1" = Particular LINQ expression
"querytype2" = Particular LINQ expression

然后通过一个简单的字符串来键入缓存。但是,考虑到我们正在执行 LINQ,我们是否可以通过 LINQ 表达式本身对缓存进行键控?我了解性能指标,但是否可以比较两个 LINQ 表达式是否相同?

【问题讨论】:

  • 如何比较 LINQ 表达式?对象是否实现了 IComparable?
  • @KyleC 这是我的问题。是否可以找出两个 LINQ 表达式在语义上是否相同(与结果集无关)
  • 你可能想看看 Lazy 类和模式:msdn.microsoft.com/en-us/library/dd642331.aspx

标签: c# linq caching


【解决方案1】:

策略:比较 SQL 输出

一种策略可能是检索呈现的 SQL 文本 + 参数,并确定它们是否与来自另一个 IQueryable 的呈现的 SQL + 参数相同。

更多信息请参见Retrieve LINQ to sql statement (IQueryable) WITH parameters

【讨论】:

  • 如果您查看我对其他问题的许多回答,当我询问性能影响时,您会感到惊讶。唉,我们正在谈论的数据集可能非常大,SELECT 语句本身将是巨大的(唉,这会从多个第三方解决方案中提取内容,所以我不能真正缩小查询) .这可能会将关键放在“1kb+”的比较范围内。认为,事实上,这将比重新查询便宜(一个数量级)。我想我想知道我们是否可以 hash 一个 LINQ 表达式。
  • 您可以散列密钥并查找冲突。
【解决方案2】:

这是我目前的解决方案。

鉴于,在存储库中,我们将有类似的调用:

public IEnumerable<MYPOCO> GetData(string someParameter, int anotherParameter);

因此我们可以说这些参数是标准。所以,我介绍了一个Criteria 类,它基本上包含Dictionary&lt;string, object&gt; 实例,并且有一些类型安全的setter 和getter,简化:

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

然后,我为Dictionary&lt;TK, TV&gt;写了一个扩展方法,基于this Stackoverflow answer。最后,IEqualityComparer&lt;Criteria&gt; 类适用于 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>

请注意,当我们想要参数完全相同的缓存策略时,这也允许我扩展这个想法,但可能是不同的 user 帐户正在访问它(我们可以添加一个字段,说 - 用户类型,符合条件,即使 LINQ 表达式不会使用它)。

【讨论】:

  • 如果要将实例作为键存储在Dictionary&lt;Criteria,whatever&gt; 中,则需要覆盖EqualsGetHashCode
  • @CharlesLambert,这将教会我在写这篇文章时不要将代码放在我面前。请查看编辑,它是IEqualityComparer&lt;&gt;
猜你喜欢
  • 2012-08-13
  • 2011-06-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多