Entity Framework Cache

Publié par Fabrice Michellonet sous le(s) label(s) le 5 septembre 2012

Malgré la version 5 d'Entity Framework sortie il y a peu de temps, beaucoup déplorent l’absence d’un mécanisme de cache implémenté dans le Framework.

Pour ceux qui ont un peu creusé le sujet, il y a bien les "Tracing and Caching Provider Wrappers for Entity Framework" parus début 2011. Cependant, ce n’est pas la solution ultime ; à l’époque Code First n’existait pas ce qui rend cette librairie incompatible avec Code First.

Pour être tout à fait franc, le code des wrappers est disponible, je pense donc qu’en bidouillant un peu, ça doit être possible d’adapter le code pour Code First.

A l’occasion de la sortie d’EntityFramework.Patterns 0.7, je vous propose de voir ensemble comme utiliser les fonctionnalités de cache fournies par cette librairie.

Soit le contexte suivant :

    public class EfContext : DbContext
    {
        public DbSet<User> Users { get; set; }
 
        public EfContext()
        {
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<EfContext>());
        }
    }

Et l’entité User tel que :

    public class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public virtual ICollection<UserRole> UserRoles { get; set; }  
    }

On peut facilement utiliser le cache en mémoire (il est possible d’en utiliser d’autre) fournit par EntityFramework.Patterns pour mettre en cache une collection de User.

            // On charge tous les users et on les stocke dans le cache.
            using (EfContext ctx = new EfContext())
            {
                IEnumerable<User> usrs = ctx.Users.ToCache();
            }
 
            // autre code...
 
            // Cette fois ci, on récupère les users à partir du cache.
            using (EfContext ctx = new EfContext())
            {
                IEnumerable<User> usrs = ctx.Users.FromCache();
            }

Simple non ?

Pour ceux qui préfèrent éviter l’accès direct au context d’Entity Framework et qui isolent leur accès à la base dans des repository, EntityFramework.Patterns vous facilitera la tâche également.

Il vous suffit de wrapper votre Repository avec le CacheableRepository qui vous apporte les fonctionnalités de cache.

            using (EfContext ctx = new EfContext())
            {
                DbContextAdapter adpt = new DbContextAdapter(ctx);
 
                IRepository<User> repo =
                    new CacheableRepository<User>(
                        new Repository<User>(adpt)
                        );
 
                // On charge tous les utilisateurs.
                // Par defaut le CacheableRepository va mettre en cache le resultset
                // en provenance de la base et le réutilisera le cas échéant plus tard.
                IEnumerable<User> usrs = repo.GetAll();
 
                // autre code.
 
                // Cette fois-ci, les users proviennent du cache. Il n'y a pas d'accès en base.
                usrs = repo.GetAll();
            }

Comme vous le voyez le CacheableRepository fait appel au cache pour vous ; et vous permet de ne pas avoir à gérer la suppression d’éléments dans le cache lorsque les éléments ont étés modifiés/supprimés/insérés etc…

Je reviendrais ultérieurement dans un prochain post sur les mécanismes avancés du cache proposés par EntityFramework.Patterns.