۱۳۹۰/۰۳/۰۳

استفاده از Dialect سفارشي در NHibernate


Dialects در NHibernate كلاس‌هايي هستند جهت معرفي تعاريف ويژگي‌هاي خاص بانك‌هاي اطلاعاتي مختلف؛ مثلا SQL Server 2008 چه ويژگي‌هاي جديدي دارد يا SQL Server CE 4.0 كه جديدا ارائه شده، امكان تعريف offset را در كوئري‌هاي خود ميسر كرده (چيزي كه قرار است در نگارش بعدي SQL Server اصلي(!) در دسترس باشد) ، اكنون چگونه مي‌توان اين ويژگي را فعال كرد (بايد Dialect آن به روز شود و ... همين). يك سري Dialect از پيش تعريف شده هم براي اكثر بانك‌هاي اطلاعاتي در NHibernate وجود دارد. ممكن است اين Dialects پيش فرض الزاما خواسته شما را برآورده نكنند يا مو به مو مستندات بانك‌ اطلاعاتي مرتبط را پياده سازي نكرده باشند و سؤال اين است كه اكنون چه بايد كرد؟ آيا بايد حتما سورس‌ها را دستكاري و بعد كامپايل كرد؟ به اين صورت هر بار با ارائه يك نگارش جديد NHibernate به مشكل برخواهيم خورد چون بايد كل عمليات تكرار شود.
خبر خوب اينكه مي‌توان از همين Dialects موجود ارث بري كرد، سپس مواردي را كه نياز داريم override كرده يا به كلاس مشتق شده افزود. اكنون مي‌توان از اين Dialect سفارشي به جاي Dialect اصلي استفاده كرد. در ادامه با يك نمونه آشنا خواهيم شد.
فرض كنيد Dialect انتخابي مرتبط است با SQL Server CE استاندارد. كوئري ساده زير را مي‌نويسيم، به ظاهر بايد كار كند:
var list = session.Query<SomeClass>().Where(x=>x.Date.Year==2011).ToList();
اما كار نمي‌كند! علت اين است كه تمام Dialects در NHibernate از يك Dialect پايه مشتق شده‌اند. در اين Dialect پايه، تعريف تابع استخراج year از يك تاريخ به نحو زير است:
extract(year, ?1)
اما در SQL CE اين تابع بايد به صورت زير تغيير كند تا كار كند:
datepart(year, ?1)
و ... اين Override انجام نشده (تا نگارش فعلي آن). مهم نيست! خودمان انجام خواهيم داد! به صورت زير:
using NHibernate;
using NHibernate.Dialect;
using NHibernate.Dialect.Function;

namespace Test1
{
public class CustomSqlCeDialect : MsSqlCeDialect
{
public CustomSqlCeDialect()
{
RegisterFunction("year", new SQLFunctionTemplate(NHibernateUtil.Int32, "datepart(year, ?1)"));
}
}
}
خوب تا اينجا ما يك Dialect جديد را با ارث بري از MsSqlCeDialect اصلي توليد كرده‌ايم. مرحله بعد نوبت به معرفي آن به NHibernate است. اينكار توسط Fluent NHibernate به سادگي زير است:
var dbType = MsSqlCeConfiguration.Standard
...
.Dialect<CustomSqlCeDialect>();

پس از آن كوئري LINQ ابتداي بحث بدون مشكل اجرا خواهد شد چون اكنون مي‌داند كه بجاي extract year ، بايد از تابع datepart‌ استفاده كند.
مرحله بعد هم مي‌تواند تهيه يك patch و ارسال به گروه اصلي براي به روز رساني پروژه NH باشد.