简体   繁体   English

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

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

I was reading about caching and performance with Entity Framework 6 and I had this ideia of always checking the DbSet.Local collection before issuing any query to the database, if the purpose of the query is to load a single entity information. 我正在阅读有关Entity Framework 6缓存和性能的信息,如果要查询的目的是加载单个实体信息,那么我总是在向数据库发出任何查询之前始终检查DbSet.Local集合。 So this is the pattern I came up with: 所以这是我想出的模式:

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;
}

I believe the overhead of checking Local is neglectable, considering the benefit of avoiding a db roundtrip + db processing. 考虑到避免db往返+ db处理的好处,我认为检查Local的开销可以忽略不计。

With that said, I proceeded to read the Identity Framework source code to check whether they did anything similar, and I found out that they always issue another query, even with a high chance of the data being already in memory, which means that this: 如此说来,我继续阅读Identity Framework源代码以检查它们是否做了类似的事情,并且发现它们总是发出另一个查询,即使很有可能数据已经在内存中,这意味着:

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

causes 4 roundtrips to the db, even if the username parameter is the username of the account loaded by FindById . 即使username参数是FindById加载的帐户的用户名,也会导致数据库往返4次。

Here's my question: am I onto something here, or this pattern just isn't safe? 这是我的问题:我是在这里踩东西吗,还是这种模式不安全? I'm not sure whether I should use this, considering Identity doesn't use anything similar, and the authors have more knowledge than me, obviously. 考虑到Identity不会使用任何类似的东西,我不确定是否应该使用它,而且作者显然比我有更多的知识。 Is DbSet.Local safe this way? 这样DbSet.Local安全吗?

--Update --update

I just found a piece of code that cracks open LINQ queries passed as parameter to check whether it includes a select by id so they can check the cache for the entity before going to the db (via call to DbSet.Find ). 我刚刚发现了一段代码,该代码可以破解作为参数传递的打开的LINQ查询,以检查其是否包含按ID进行选择,以便他们可以在进入db之前(通过调用DbSet.Find )检查实体的缓存。 So, I guess I'm onto something, just can't understand why they didn't extend this idea to methods such as "FindByEmail". 所以,我想我正在研究某些东西,只是不明白为什么他们没有将这个想法扩展到“ FindByEmail”之类的方法。

Really interesting question, I'm having some issues with just this. 真正有趣的问题是,我对此有一些疑问。

It looks safe for the example you posted. 对于您发布的示例,它看起来很安全。 You are looking for a single entity with a known key value. 您正在寻找具有已知键值的单个实体。 I think you find it isn't so safe in different circumstances, though. 我认为您会发现,在不同情况下它并不是那么安全。

For example, I've inherited some code where the repository uses local (cached) results first, and then falls back on issuing the query to the database if there is no result: 例如,我继承了一些代码,其中存储库首先使用本地(缓存的)结果,然后如果没有结果,则退回向数据库发出查询:

    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>();
    }

This is great, most of the time, but I have hit a problem when issuing two requests to LoadAll for overlapping results. 在大多数情况下,这很好,但是在向LoadAll发出两个请求以获取重叠结果时遇到了一个问题。 eg load an image list with images 1 and 2 in, then load an image list with images 2 and 3 in. Both queries are fulfilled using the local cache, but the second one incorrectly only includes image 2. Image 3 isn't in the local cache yet. 例如,加载包含图像1和2的图像列表,然后加载包含图像2和3的图像列表。这两个查询都是使用本地缓存来完成的,但是第二个查询错误地仅包含图像2。本地缓存了。

I either need to rework the calling code to pre-load all images to the cache, or I need to remove the locally cached results from any method which returns a list. 我或者需要重做调用代码以将所有图像预加载到缓存中,或者需要从任何返回列表的方法中删除本地缓存的结果。

I can't see an obvious way to work out when the cached query result isn't good enough and issue the non-cached query instead. 当缓存的查询结果不够好并发出非缓存的查询时,我看不出一种明显的解决方法。

MS has posted an article where the local results are bound directly to a UI ( https://msdn.microsoft.com/en-us/library/jj592872(v=vs.113).aspx ). MS已发布了一篇文章,其中将本地结果直接绑定到UI( https://msdn.microsoft.com/zh-cn/library/jj592872 ( v=vs.113 ) .aspx )。 This fits well in the instance where you want to be able to make changes and commit them all in one go. 这非常适合您希望能够进行更改并一次提交所有更改的情况。 Not so sure it extends brilliantly well beyond that. 不太确定它是否可以很好地扩展。

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

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