web-dev-qa-db-fra.com

Comment mettre en cache les tables de base de données pour empêcher de nombreuses requêtes de base de données dans Asp.net C # mvc

Je construis mes propres cms en utilisant Asp.net mvc 4 (c #), et je veux mettre en cache certaines données de base de données, comme: localisation, catégories de recherche (c'est long-tail, chaque catégorie a ses propres sous et sous-sous catégories), etc. ..

Il sera exagéré d'interroger la base de données tout le temps, car il peut y avoir plus de 30 à 100 requêtes pour chaque demande de page, mais les utilisateurs mettent rarement à jour cette base de données

Alors, quelle est la meilleure façon (performance et commodité) de le faire?

Je sais comment utiliser le OutputCache de l'action, mais ce n'est pas ce dont j'ai besoin dans cette situation, c'est mettre le cache en html, mais ce dont j'ai besoin, par exemple, c'est que mon propre assistant @html.Localization("Newsletter.Tite") prendra la valeur du langue, ou tout autre assistant qui interagit avec les données, etc.

Je pense (pas vraiment sûr) que je dois mettre en cache les données que je veux, uniquement lorsque l'application est invoquée pour la première fois, puis travailler avec l'emplacement du cache, mais je n'ai aucune expérience, même à ce sujet.

27
Daniel Ezra

Vous pouvez utiliser la fonction intégrée MemoryCache pour stocker des ensembles de résultats entiers que vous avez récupérés de la base de données.

Un modèle typique:

MyModel model = MemoryCache.Default["my_model_key"] as MyModel;
if (model == null)
{
    model = GetModelFromDatabase();
    MemoryCache.Default["my_model_key"] = model;
}

// you could use the model here
31
Darin Dimitrov

J'ai dû mettre en cache des données de base de données communes comme des données affichées dans des listes déroulantes. J'ai utilisé MemoryCache. Et j'ai utilisé Entity Framework code first et Autofac pour l'injection de dépendances.

Voici une partie de ce que j'ai fait dans ma solution, peut ne pas fonctionner pour vous mais cela a fonctionné pour moi, pas parfait cependant mais a besoin de beaucoup de nettoyage pour le faire.

Mon interface ICacheManager:

public interface ICacheManager
{
     T Get<T>(string key);

     void Set(string key, object data, int cacheTime);

     bool IsSet(string key);

     void Remove(string key);

     void Clear();
}

Ma classe CacheManager:

public class CacheManager : ICacheManager
{
     private ObjectCache Cache
     {
          get
          {
               return MemoryCache.Default;
          }
     }

     public T Get<T>(string key)
     {
          return (T)Cache[key];
     }

     public void Set(string key, object data, int cacheTime)
     {
          if (data == null)
          {
               return;
          }

          CacheItemPolicy policy = new CacheItemPolicy();
          policy.AbsoluteExpiration = DateTime.Now + TimeSpan.FromMinutes(cacheTime);

          Cache.Add(new CacheItem(key, data), policy);
     }

     public bool IsSet(string key)
     {
          return (Cache.Contains(key));
     }

     public void Remove(string key)
     {
          Cache.Remove(key);
     }

     public void Clear()
     {
          foreach (var item in Cache)
          {
               Remove(item.Key);
          }
     }
}

Une classe d'extension pour ma mise en cache:

public static class CacheExtensions
{
     public static T Get<T>(this ICacheManager cacheManager, string key, Func<T> acquire)
     {
          return Get(cacheManager, key, 60, acquire);
     }

     public static T Get<T>(this ICacheManager cacheManager, string key, int cacheTime, Func<T> acquire)
     {
          if (cacheManager.IsSet(key))
          {
               return cacheManager.Get<T>(key);
          }
          else
          {
               var result = acquire();

               cacheManager.Set(key, result, cacheTime);

               return result;
          }
     }
}

Et c'est ainsi que je l'utiliserais dans ma classe de référentiel. Cette méthode renvoie une liste de toutes mes banques qui s'affiche dans une liste déroulante.

public class BankRepository : RepositoryBase<Bank>, IBankRepository
{
     private readonly ICacheManager cacheManager;
     private const string BanksAllCacheKey = "banks-all";

     public BankRepository(IDatabaseFactory databaseFactory, ICacheManager cacheManager)
          : base(databaseFactory)
     {
          Check.Argument.IsNotNull(cacheManager, "cacheManager");

          this.cacheManager = cacheManager;
     }

     public IEnumerable<Bank> FindAll()
     {
          string key = string.Format(BanksAllCacheKey);

          return cacheManager.Get(key, () =>
          {
               var query = from bank in DatabaseContext.Banks
                           orderby bank.Name
                           select bank;

               return query.ToList();
          });
     }
}

J'espère que ça aide. C'est une implémentation très simple mais ça marche pour moi. De nombreux articles en ligne expliquent comment utiliser une stratégie de mise en cache dans ASP.NET MVC. Juste Google it.

32
Brendan Vogt

Il y a plusieurs choses à considérer ici avant de choisir votre implémentation de la mise en cache, mais l'une des principales choses que vous devez décider est à quel moment voulez-vous que la mise en cache se produise - lors de l'accès aux données, la création du modèle ou la génération de l'interface utilisateur? Un ou tous ces endroits?

Vous avez plusieurs options mais pour la mise en cache générale des données, vous pouvez utiliser le System.Runtime.Caching.MemoryCache , ou pour quelque chose de beaucoup plus flexible et gratifiant, vous pouvez regarder une implémentation utilisant NoSQL comme Redis .

Vous pouvez utiliser MemoryCache pour la mise en cache des données, mais utilisez Redis pour la mise en cache des agrégats constituant vos modèles de vue. Si vous êtes allé avec Redis, vous pourriez bien sûr gérer toute votre mise en cache en utilisant cela. L'avantage étant que toutes vos données deviendraient persistantes au redémarrage de l'application. L'inconvénient est que cela devient une exigence supplémentaire pour exécuter votre CMS.

D'autres facteurs à prendre en compte sont la cohérence (l'utilisation de l'IoC aiderait) et la possibilité d'annuler les données une fois mises à jour. Donc avoir un moyen de mettre à jour le cache.

En ce qui concerne la meilleure approche , dans votre cas, si vous créez une nouvelle application CMS, commencez petit/simple et construisez par étapes. Il se peut que ce ne soit pas parfait pour la première fois, mais tant que votre approche est cohérente et claire, il devrait être facile de s'appuyer sur ce que vous avez fait ou d'échanger et d'essayer quelque chose de différent/meilleur.

4
Digbyswift