web-dev-qa-db-fra.com

Pourquoi Entity Framework 6.x ne met-il pas en cache les résultats?

Peut-être que je comprends mal la mise en cache que DbContext et DbSet fait, mais j'avais l'impression qu'il y avait une mise en cache qui continuerait. Je constate un comportement auquel je ne m'attendais pas lorsque j'exécute le code suivant:

var ctx = CreateAContext();
var sampleEntityId = ctx.SampleEntities.Select(i => i.Id)
                                       .Single(i => i == 3); //Calls DB as expected
var cachedEntityId = ctx.SampleEntities.Select(i => i.Id)
                                       .Single(i => i == 3); //Calls DB unexpectedly

Que se passe t-il ici? Je pensais qu'une partie de ce que vous obtenez de DbSet est qu'il vérifierait d'abord le cache local pour voir si cet objet existe avant d'interroger la base de données. Y a-t-il juste une sorte d'option de configuration qui me manque ici?

39
Adam Modlin

Ce que @ emcas88 essaie de dire est que EF ne vérifiera le cache que lorsque vous utilisez le .Find méthode sur DbSet.

En utilisant .Single, .First, .Where, etc. ne mettra pas les résultats en cache sauf si vous utilisez une mise en cache de second niveau.

42
danludwig

En effet, la mise en œuvre des méthodes d'extenseur, utilisez la méthode Find du contexte

contextName.YourTableName.Find()

pour vérifier d'abord le cache. J'espère que ça aide.

29
emcas88

Parfois j'utilise ma méthode d'extension:

using System.Linq;
using System.Linq.Expressions;

namespace System.Data.Entity
{
    public static class DbSetExtensions
    {
        public static TEntity FirstOrDefaultCache<TEntity>(this DbSet<TEntity> queryable, Expression<Func<TEntity, bool>> condition) 
            where TEntity : class
        {
            return queryable
                .Local.FirstOrDefault(condition.Compile()) // find in local cache
                   ?? queryable.FirstOrDefault(condition); // if local cache returns null check the db
        }
    }
}

Usage:

db.Invoices.FirstOrDefaultCache(x => x.CustomerName == "Some name");

Vous pouvez également remplacer FirstOrDefault par SingleOrDetfault.

23
cryss

Jetez un œil à EF Docs , vous y trouverez une réponse:

Notez que DbSet et IDbSet créent toujours des requêtes sur la base de données et impliquent toujours un aller-retour vers la base de données même si les entités retournées existent déjà dans le contexte. Une requête est exécutée sur la base de données lorsque:

  • Il est énuméré par un foreach (C #) ou For Each (Visual Basic).
  • Il est énuméré par une opération de collecte telle que ToArray, ToDictionary ou ToList.
  • Les opérateurs LINQ tels que First ou Any sont spécifiés dans la partie la plus externe de la requête.
  • Les méthodes suivantes sont appelées: la méthode d'extension Load sur un DbSet, DbEntityEntry.Reload, et Database.ExecuteSqlCommand.
11

EF6 ne fait pas de mise en cache des résultats ootb. Pour mettre en cache les résultats, vous devez utiliser un cache de deuxième niveau. Voir ce projet prometteur sur CodePlex:

Mise en cache de deuxième niveau pour EF 6.1

Gardez à l'esprit que si les données changent sur la base de données, vous ne le saurez pas immédiatement. Parfois, cela est important selon le projet. ;)

7
Dave