۱۳۹۰/۱۱/۳۰

NHibernate و مديريت خودكار تغييرات ساختار بانك اطلاعاتي


يكي از دردهاي عظمايي كه حين كار با بانك‌هاي اطلاعاتي رابطه‌اي وجود دارد، هماهنگ نبودن ديتابيس توسعه، با ديتابيس كاري است. البته ابزار‌هاي متعددي براي تهيه Diff بين اين دو وجود دارند. ولي زمانيكه قرار باشد اين كار را در چندجا هم انجام دهيم، باز هم مشكل خواهد بود.
با NHibernate مي‌شود كل اين مساله را فراموش كرد! مي‌شود راحت خاصيتي را به كلاسي اضافه كرد و در اولين بار اجراي برنامه، خود NHibernate هماهنگ سازي‌ها را انجام دهد. فيلد اضافه كند. جدول اضافه كند. روابط مرتبط را اضافه كند. يعني تا اين حد كه ما فقط فايل اجرايي برنامه را به روز كنيم، كافي باشد. البته در لابلاي مطالبي كه تا به حال در مورد NHibernate در اين سايت منتشر شده به اين موضوع هم پرداخته شده و مطلب جاري، خلاصه‌ي بزرگنمايي شده آن‌ها است.

اولين قدم: آيا ساختار ديتابيس جاري، با مدل برنامه تطابق دارد؟
قبل از اينكه از NHibernate بخواهيم ساختار بانك اطلاعاتي ما را تغيير دهيد، بايد بدانيم كه آيا واقعا نيازي به اينكار هست يا خير؟
توضيحات بيشتر در مورد روش تشخيص در اينجا: (^)

قدم دوم: اگر ساختار ديتابيس جاري با مدل برنامه تطابق ندارد، چگونه بايد آن‌را به صورت خودكار به روز كرد؟
متد زير بر اساس Configuration ابتدايي بانك اطلاعاتي و نگاشت‌هاي شما، كار به روز رساني خودكار ساختار بانك اطلاعاتي را انجام خواهد داد:

public void UpdateDatabaseSchema(NHibernate.Cfg.Configuration config)
{
     var schemaUpdate = new NHibernate.Tool.hbm2ddl.SchemaUpdate(config);
     schemaUpdate.Execute(script: false, doUpdate: true);
}

يك نكته را هم بايد درنظر داشت. در اين روش هيچ فيلد و جدولي حذف نمي‌شود و به اين ترتيب، جهت امنيت بيشتر طراحي شده. اگر واقعا نياز داشتيد فيلد يا جدولي را حذف كنيد بايد دستي، همانند سابق اقدام كنيد.

قدم سوم: چگونه و در كجا، دو قدم قبل را با برنامه يكپارچه كنيم؟
بلافاصله پس از ايجاد SessionFactory در برنامه، متد زير را فراخواني كنيد:

public void TryValidateAndUpdateDatabaseSchema(NHibernate.Cfg.Configuration config)
{
     try
     {
            ValidateDatabaseSchemaAgainstMappings();
     }
     catch
     {
            UpdateDatabaseSchema(config);
     }
}

متد ValidateDatabaseSchemaAgainstMappings در صورت عدم تطابق مدلي با بانك اطلاعاتي، يك exception را صادر مي‌كند. بنابراين در اينجا كافي است متد UpdateDatabaseSchema را در قسمت catch فراخواني كرد.
و از اين پس ديگر مي‌توانيد به روز رساني ساختار بانك اطلاعاتي برنامه را فراموش كنيد! فيلد اضافه كنيد، كلاس اضافه كنيد، تمام اين‌ها در اولين بار اجراي برنامه به روز شده، به صورت خودكار به بانك اطلاعاتي اعمال خواهند شد.