繁体   English   中英

可以在EF6上发出查询之前始终检查DbSet.Local

[英]Safe to always check DbSet.Local before issuing query on EF6

我正在阅读有关Entity Framework 6缓存和性能的信息,如果要查询的目的是加载单个实体信息,那么我总是在向数据库发出任何查询之前始终检查DbSet.Local集合。 所以这是我想出的模式:

pubilc TAccount LoadByUsername<TAccount>(string username)
{
    TAccount acc = null;

    // Check cache.
    acc = DbEntitySet.Local.FirstOrDefault(a => a.Username.Equals(username, StringComparison.CurrentCultureIgnoreCase));

    if (acc == null) {

        // Then try and load from db.
        return await DbEntitySet.FirstOrDefaultAsync(u => u.Username.Equals(username)).WithCurrentCulture();
    }

    return acc;
}

考虑到避免db往返+ db处理的好处,我认为检查Local的开销可以忽略不计。

如此说来,我继续阅读Identity Framework源代码以检查它们是否做了类似的事情,并且发现它们总是发出另一个查询,即使很有可能数据已经在内存中,这意味着:

FindById(accId);
FindByUsername(username);
FindByUsername(username);
FindByUsername(username);

即使username参数是FindById加载的帐户的用户名,也会导致数据库往返4次。

这是我的问题:我是在这里踩东西吗,还是这种模式不安全? 考虑到Identity不会使用任何类似的东西,我不确定是否应该使用它,而且作者显然比我有更多的知识。 这样DbSet.Local安全吗?

--update

我刚刚发现了一段代码,该代码可以破解作为参数传递的打开的LINQ查询,以检查其是否包含按ID进行选择,以便他们可以在进入db之前(通过调用DbSet.Find )检查实体的缓存。 所以,我想我正在研究某些东西,只是不明白为什么他们没有将这个想法扩展到“ FindByEmail”之类的方法。

真正有趣的问题是,我对此有一些疑问。

对于您发布的示例,它看起来很安全。 您正在寻找具有已知键值的单个实体。 我认为您会发现,在不同情况下它并不是那么安全。

例如,我继承了一些代码,其中存储库首先使用本地(缓存的)结果,然后如果没有结果,则退回向数据库发出查询:

    public List<T> LoadAll(Expression<Func<T, bool>> expression)
    {
        var localResult = _dbSet.Local.AsQueryable().Where(expression).ToList<T>();

        return localResult.Count > 0 ? localResult : _dbSet.Where(expression).ToList<T>();
    }

在大多数情况下,这很好,但是在向LoadAll发出两个请求以获取重叠结果时遇到了一个问题。 例如,加载包含图像1和2的图像列表,然后加载包含图像2和3的图像列表。这两个查询都是使用本地缓存来完成的,但是第二个查询错误地仅包含图像2。本地缓存了。

我或者需要重做调用代码以将所有图像预加载到缓存中,或者需要从任何返回列表的方法中删除本地缓存的结果。

当缓存的查询结果不够好并发出非缓存的查询时,我看不出一种明显的解决方法。

MS已发布了一篇文章,其中将本地结果直接绑定到UI( https://msdn.microsoft.com/zh-cn/library/jj592872 ( v=vs.113 ) .aspx )。 这非常适合您希望能够进行更改并一次提交所有更改的情况。 不太确定它是否可以很好地扩展。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM