Pull to refresh

Кэширование Linq2Sql таблиц с автоматической инвалидацией кэша

Reading time8 min
Views1.2K
Как продолжение этого топика про кэш хочу предложить вам свое, частично стыренное решение для кеширования не очень больших таблиц. Для этого просто создадим новый extension метод:
Copy Source | Copy HTML
  1. public static class CachingHelper
  2.     {
  3.         /// <summary>
  4.         /// строка соединения с базой
  5.         /// </summary>
  6.         private static string conString = System.Configuration.ConfigurationManager.ConnectionStrings["pltfrmDBConnectionString"].ConnectionString;
  7.  
  8.         /// <summary>
  9.         /// Cache instance object 
  10.         /// </summary>
  11.         private static volatile Cache cache = HttpContext.Current.Cache;
  12.  
  13.         /// <summary>
  14.         /// Object for proper locking of cache additions/removals
  15.         /// </summary>
  16.         private static object syncRoot = new object();
  17.  
  18.         /// <summary>
  19.         /// Кэширует и получает объекты из кэша
  20.         /// </summary>
  21.         /// <param name="query">Таблица для кэширования</param>
  22.         /// <typeparam name="T">Тип объектов в Таблице</typeparam>
  23.         /// <returns>Массив объектов типа T</returns>
  24.         public static T[] LinqCache<T>(this Table<T> query) where T : class
  25.         {
  26.             var tableName = query.Context.Mapping.GetTable(typeof(T)).TableName;
  27.             var result = cache[tableName] as T[];
  28.             if (result != null)
  29.             {
  30.                 return result;
  31.             }
  32.  
  33.             var trop = new TransactionOptions
  34.                            {
  35.                                IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted
  36.                            };
  37.             var req = TransactionScopeOption.Required;
  38.  
  39.             if (Transaction.Current == null || Transaction.Current.TransactionInformation.Status == TransactionStatus.Aborted)
  40.             {
  41.                 req = TransactionScopeOption.RequiresNew;
  42.             }
  43.  
  44.             using (var ts = new TransactionScope(req, trop))
  45.             {
  46.                 using (var cn = new SqlConnection(conString))
  47.                 {
  48.                     try
  49.                     {
  50.                         cn.Open();
  51.                         var cmdText = query.Context.GetCommand(query).CommandText;
  52.                         var cmd = new SqlCommand(cmdText, cn)
  53.                                       {
  54.                                           NotificationAutoEnlist = true,
  55.                                           Notification = null,
  56.                                           CommandType = CommandType.Text
  57.                                       };
  58.  
  59.                         foreach (DbParameter dbp in query.Context.GetCommand(query).Parameters)
  60.                         {
  61.                             cmd.Parameters.Add(new SqlParameter(dbp.ParameterName, dbp.Value));
  62.                         }
  63.  
  64.                         var dependency = new SqlCacheDependency(cmd);
  65.  
  66.                         cmd.ExecuteNonQuery();
  67.  
  68.                         result = query.ToArray();
  69.  
  70.                         cache.Insert(tableName, result, dependency);
  71.                     }
  72.                     catch (SqlException e)
  73.                     {
  74.                         if (e.Number == 4060)
  75.                         {
  76.                             throw new AuthenticationException("Авторизация не пройдена");
  77.                         }
  78.  
  79.                         throw;
  80.                     }
  81.                 }
  82.  
  83.                 ts.Complete();
  84.             }
  85.  
  86.             return result;
  87.         }
  88. }


Пользоваться этим проще простого:
1) добавляем в Global.asax
Copy Source | Copy HTML
  1. /// <summary>
  2. /// Событие старта приложения
  3. /// </summary>
  4. /// <param name="sender">
  5. /// Вызывающий объект
  6. /// </param>
  7. /// <param name="e">
  8. /// Аргументы события
  9. /// </param>
  10. protected void Application_Start(object sender, EventArgs e)
  11. {
  12.     SqlDependency.Start(ConfigurationManager.ConnectionStrings["pltfrmDBConnectionString"].ConnectionString);
  13. }
  14.  
  15. /// <summary>
  16. /// Событие завершения приложения
  17. /// </summary>
  18. /// <param name="sender">
  19. /// Вызывающий объект
  20. /// </param>
  21. /// <param name="e">
  22. /// Аргументы события
  23. /// </param>
  24. protected void Application_End(object sender, EventArgs e)
  25. {
  26.     SqlDependency.Stop(ConfigurationManager.ConnectionStrings["pltfrmDBConnectionString"].ConnectionString);
  27. }

2) используем в приложении:

Copy Source | Copy HTML
  1. var db = new SomeContext();
  2. var cached = db.SomeTable.LinqCache().Where(a => a.b == "qwe");

PS для работы данного метода у вас должен быть включен SQL server broker
PPS транзакции использовать необязательно, это куски кода с текущего проекта:)
Tags:
Hubs:
Total votes 13: ↑9 and ↓4+5
Comments5

Articles