۱۳۹۰/۰۲/۱۱

فعال سازي سطح دوم كش در Fluent NHibernate


سطح اول كش در NHibernate در يك تراكنش معنا پيدا مي‌كند (+)؛ اما نتايج حاصل از اعمال سطح دوم (+) آن، در اختيار تمام تراكنش‌هاي جاري برنامه خواهند بود. در ادامه قصد داريم نحوه فعال سازي سطح دوم كش NHibernate را توسط Fluent NHibernate بررسي كنيم.

الف) دريافت كش پروايدر
براي اين منظور به صفحه اصلي آن در سايت سورس فورج مراجعه نمائيد(+). اگر به علت تحريم‌ها امكان دريافت فايل‌هاي مرتبط را نداشتيد از اين برنامه استفاده كنيد(+). پس از دريافت، مي‌خواهيم نحوه فعال سازي NHibernate.Caches.SysCache.dll را بررسي كنيم (اين اسمبلي، در برنامه‌هاي وب و دسكتاپ بدون مشكل كار مي‌كند).

ب) اعمال به قسمت تعاريف اوليه
پس از دريافت اسمبلي NHibernate.Caches.SysCache.dll و افزودن ارجاعي به آن، اكنون نوبت به معرفي آن به تنظيمات Fluent NHibernate‌ مي‌باشد. اين‌كار هم بسيار ساده است:
...
.ConnectionString(x => x.FromConnectionStringWithKey(...))
.Cache(x => x.UseQueryCache()
.UseMinimalPuts()
.ProviderClass<NHibernate.Caches.SysCache.SysCacheProvider>())
...

ج) تعريف نوع كش در هنگام ايجاد نگاشت‌ها
اگر از ClassMap‌ها براي تعريف نگاشت‌ها استفاده مي‌كنيد، در انتهاي تعاريف يك سطر Cache.ReadWrite را اضافه كنيد.
اگر از AutoMapping استفاده مي‌كنيد، نياز است تا با استفاده از IAutoMappingOverride (+) سطر ياد شده اضافه گردد؛ براي مثال:
using FluentNHibernate.Automapping.Alterations;

namespace NH3Test.MappingDefinitions.Domain
{
public class AccountOverrides : IAutoMappingOverride<Account>
{
public void Override(FluentNHibernate.Automapping.AutoMapping<Account> mapping)
{
mapping.Cache.ReadWrite();
}
}
}
تعريف يك سطر فوق هم مهم است؛ زيرا در غيراينصورت فقط primary key حاصل از بار اول فراخواني كوئري‌هاي مرتبط كش مي‌شوند؛ نه نتيجه عمليات. هرچند اين مورد هم يك قدم مثبت به شمار مي‌رود از اين لحاظ كه براي مثال تهيه نتايج كوئري بر روي فيلدي كه ايندكس بر روي آن تعريف نشده است هميشه از حالت تهيه كوئري بر روي فيلد داراي ايندكس كندتر است. اما هدف ما در اينجا اين است كه پس از بار اول فراخواني كوئري، بار‌هاي دوم و بعدي ديگر كوئري خاصي را به بانك اطلاعاتي ارسال نكرده و نتايج از كش خوانده شوند (جهت استفاده عموم كاربران در كليه تراكنش‌هاي جاري برنامه).

د) اعمال متد Cacheable به كوئر‌ي‌ها
سه مرحله قبل نحوه برپايي مقدماتي سطح دوم كش را بيان مي‌كنند و تنها يكبار نياز است انجام شوند. در ادامه هر جايي كه نياز داشتيم نتايج كوئري مورد نظر كش شوند (و بايد دقت داشت كه اين كش شدن سطح دوم به معني در دسترس بودن نتايج آن جهت تمام كاربران برنامه در تمام تراكنش‌هاي جاري برنامه هستند؛ براي مثال نتايج آمار سايت كه دسترسي عمومي دارد) تنها كافي است متد Cacheable را به كوئري مورد نظر اضافه كرد؛ براي مثال:
var data = session.QueryOver<Account>()
.Where(s => s.Name == "name")
.Cacheable()
.List();

ه) چگونه صحت اعمال سطح دوم كش را بررسي كنيم؟
براي بررسي اين امر بايد به خروجي SQL نهايي مراجعه كرد (+). سه تراكنش مجزا را تعريف كنيد. در تراكنش اول يك insert ساده، در تراكنش دوم كوئري از اطلاعات قبل (به همراه اعمال متد Cacheable) و در تراكنش سوم مجددا همان كوئري تراكنش دوم را (به همراه اعمال متد Cacheable) تكرار كنيد. حاصل كار تنها بايد دو عبارت SQL باشند. يك مورد جهت insert و يك مورد هم select . در تراكنش سوم، از نتايج كش شده تراكنش دوم استفاده خواهد شد؛ به همين جهت ديگري كوئري سومي به بانك اطلاعاتي ارسال نخواهد شد.
اگر اعمال مورد (ج) فوق را فراموش كنيد، سه كوئري را مشاهده خواهيد كرد، اما كوئري سوم با كوئري دوم اندكي متفاوت خواهد بود و بهينه‌تر؛ چون به صورت هوشمند بر اساس جستجوي بر روي primary key تغيير كرده است (صرفنظر از اينكه قسمت where كوئري شما چيست).