پیاده سازی و پیکربندی NHibernate (با یک نمونه)
اهداف:
1. ایجاد فایل mapper
3. ایجاد رابطه یک به چند در فایلهای مپر ان.هایبرنیت
4. ایجاد رابطه چند به چند در فایلهای مپر ان.هایبرنیت
5. ایجاد زیرکلاس در فایلهای مپر
University
Professor
Student
که ارتباطاتشان به صورت زیر تعریف شده است :

تمرین یک : روابط بین کلاسها
توضیحات :
یک دانشگاه دارای یک یا چند استاد است و یک استاد در یک یا چند دانشگاه مشغول به کار است، یک دانشگاه یک یا چند کلاس دارد و کلاسها متعلق به یک دانشگاه هستند ، کلاس را یک استاد اداره میکند و هر استاد میتواند چند کلاس را اداره کند ، دانشجویان میتوانند یک یا چند کلاس داشته باشند و هر کلاس میتواند یک یا چند دانشجو داشته باشد .
تعریف کلاسها به صورت زیر میباشد :
{
private int id;
private string name;
private IDictionary classes;
private IDictionary professors;
}
{
private int id;
private string firstname;
private string lastname;
private string id;
private IDictionary departments;
private IDictionary classes;
}
public class UniversityClass
{
private int id;
private string name;
private string number;
private string syllabus;
private DateTime startDate;
private Professor professor;
private IDictionary students;
private Department department;
}
public class Student : Person
{
private int id;
private string firstname;
private string lastname;
private string ssn;
private IDictionary classes;
}
public interface Person
{
public int Id;
public string FirstName;
public string LastName;
}

تمرین یک : روابط بین جداول پایگاه داده
فایلهای map شده
مرحلهٔ بعد فراهم کردن فایلهای مپ شده است که با اطلاعات موجود در جداول در ارتباط هستند. هر کلاس، فایلهای مپ شدهٔ خود را نیاز دارد. این فایلها میتوانند هرجا که شما بخواهید ذخیره شوند. اما بهتر است برای سادگی کار یک library به پروژه add کنید و این فایلها را در آنجا ذخیره کنید. توجه داشته باشید که فایلهای مپ شده برای ویژگیهایی که قرار است ماندگار (Persistence) باشند (ذخیره شوند) تهیه میشوند.
<?xml version=«1.0« encoding=«utf-8« ?>
<hibernate-mapping xmlns=«urn:nhibernate-mapping-2.0«>
حالا برای mapping مراحل زیر را طی میکنیم:
در ابتدا مشخص میکنیم که کدام کلاس را مپ میکنیم. این کار را با نوشتن کلمهٔ class و نسبت دادن یک نام به آن انجام میدهیم.
<!–[if gte mso 9]> Normal 0 false false false EN-US X-NONE AR-SA <![endif]–><!–[if gte mso 9]> <![endif]–> <!–[endif]–>
<class name=«nhRegistration.Department, nhRegistration» table=«Department« />
حالا مشخصهها را به یک فیلد DataBase مپ میکنیم. برای این کار باید نام مشخصه، ستون و نوع آن بیان شود. توجه داشته باشید که مقدار name در برنامه قابل دسترسی است و مقدار column باید و باید مشابه نام ستونی باشد که در جدول پایگاه داده ایجاد کردهاید. با این کار میتوان نامهای متفاوتی را برای ستونهای جداول در پایگاه داده و آنچه که در عمل با آن در حال کار هستید، ایجاد کرد. فیلد type هم بیانگر نوع فیلد شما در جدول پایگاه داده است.
<!–[if gte mso 9]> Normal 0 false false false EN-US X-NONE AR-SA <![endif]–><!–[if gte mso 9]> <![endif]–><!–[endif]–>
<property name=«Name« column=«DeptName« type=«String(50)«/>
مورد جالب در اینجا فیلد id از کلاس Department است. هر کلاس باید فیلدی داشته باشد که شامل دادهای باشد که یکتاست. در مثال ما هر کلاس یک شناسه id دارد که یکتاست. در اینجا شما باید یک مجموعهٔ استاندارد از صفات را فراهم کنید که مهمترینشان Generator نام دارد و مشخص میکند که این داده چطور درست شده (توسط برنامهنویس یا بوسیله NHibernate یا توسط لایههای پایینتر).
Applicationهای مختلف قوانین مختلفی دربارهٔ شناسهها دارند و پایگاههایداده مختلف سرویسهای unique ای را برای مدیریت مقادیر پیشنهاد میکنند. در اینجا به چند مورد اشاره میکنیم.
مقادیر رایج برای generator ها:
1. Identity
2. Sequence
3. Hilo : استفاده از الگوریتم hilo برای generate کردن مقادیر شناسهها.
4. Native : انتخاب خود DataBase
شناسهٔ unsaved_value یک مقدار default برای مشخصهٔ id است. یعنی وقتی که یک object ساخته شده ولی هنوز ذخیره نشده.
در اینجا ما native را انتخاب میکنیم. تا آنچه را که در پایگاه داده تعیین کردهایم به عنوان id قرار بگیرد.
<id name=«Id« column=«DeptID« type=«Int32«>
<generator class=«assigned« />
</id>
حالا کد ما به این شکل درآمده:
<?xml version=«1.0« encoding=«utf-8« ?>
<hibernate-mapping xmlns=«urn:nhibernate-mapping-2.0«>
<class name=«nhRegistration.Department, nhRegistration» table=«Department«>
<id name=«Id« column=«DeptID« type=«Int32«>
<generator class=«assigned« />
</id>
<property name=«Name« column=«DeptName« type=«String(50)«/>
</class>
</hibernate-mapping>
سپس به جمعآوری property ها میپردازیم (هر کدام که بخصوص باشند). بیایید به اولین کلاسمان نگاهی بیاندازیم که مجموعهای از کلاسها در دانشگاه است. نیازها و مدلها را به خاطر داریم: یک دانشگاه میتواند چندین کلاس داشته باشد اما کلاس متعلق به یک دانشگاه است. این یک ارتباط یک به چند است. برای مدل کردن آن نیاز به element های <set> داریم که نشان دهیم که مجموعهای را مپ میکنیم.
<set name=«Classes« cascade=«all«>
<key column=«DeptID«/>
<one-to-many class=«nhRegistration.UniversityClass,nhRegistration«/>
</set>
به عبارت سادهتر با کد بالا، مقادیر کلید DeptID که در جدول خودش PrimaryKey است، به ستون مشخص شدهاش Map میشود. نشانهٔ name در <set> نام یک فیلد است که مجموعه را نگه میدارد. در اینجا column در <key> نام یک ستون در مجموعهای است که به مشخصهٔ id کلاس والد مپ میشود و <one_to_many> نوع کلاس گردآوری شده است. به این معنی که رابطه این ستون (فیلد) با ستون دیگر به چه صورتی است ( پایینتر به انواع دیگری هم اشاره میکنیم)
بنابراین جدولuniversity یک فیلد به نام deptid دارد که به id در کلاس university ی ما مپ میشود.
سرانجام ما باید فیلد professors را مپ کنیم. مدلمان را به خاطر بیاورید، دانشگاه میتواند چندین استاد داشته باشد و اساتید نیز میتوانند در چندین دانشگاه مشغول به کار باشند. این یک ارتباط چند به چند است. که در زیر نمونهای از آن را مشاهده میکنید، در پیاده سازی صرفا کلمه کلیدی one-to-many و many-to-many تفاوت میکند.
<set name=«Professors« table=«departmentprofessor«>
<key column=«DeptID«/>
<many-to-many class=«nhRegistration.Person,nhRegistration» column=«Personid«/>
</set>
حال مپینگ کامل زیر را بخوانید
<?xml version=«1.0« encoding=«utf-8« ?>
<hibernate-mapping xmlns=«urn:nhibernate-mapping-2.0«>
<class name=«nhRegistration.Department, nhRegistration«
table=«Department«>
<id name=«Id« column=«DeptID« type=«Int32«>
<generator class=«assigned« />
</id>
<property name=«Name« column=«DeptName« type=«String(50)«/>
<set name=«Classes« cascade=«all«>
<key column=«DeptID«/>
<one-to-many class=«nhRegistration.UniversityClass,nhRegistration«/>
</set>
<set name=«Professors« table=«departmentprofessor«>
<key column=«DeptID«/>
<many-to-many class=«nhRegistration.Person,nhRegistration« column=«Personid«/>
</set>
</class>
</hibernate-mapping>
اگر ما با استفاده از این مپینگها سعی کنیم که پروژه را load کنیم، موفق نمیشویم. NHibernate یک exception را گزارش میدهد زیرا ارتباطات یک به چند و چند به چند داریم. وقتی ارتباطاتی شبیه این داریم که NH هر دو طرف آن است باید نوع آنها را هم مپ کنیم.
<!–[if gte mso 9]> Normal 0 false false false EN-US X-NONE AR-SA <![endif]–><!–[if gte mso 9]> <![endif]–><!–[endif]–>
<?xml version=«1.0« encoding=«utf-8« ?>
<hibernate-mapping xmlns=«urn:nhibernate-mapping-2.0«>
<class name=«nhRegistration.UniversityClass, nhRegistration«
table=«UniversityClass«>
<id name=«Id« column=«DeptId« type=«Int32«>
<generator class=«assigned« />
</id>
<property name=«Name« column=«ClassName» type=«String(50)«/>
<many-to-one name=«Dept« class=«nhRegistration.Department,nhRegistration« column=«DeptID«/>
</class>
</hibernate-mapping>
تنها element جدید در این فایل <many_to_one> است که نمایندهٔ طرف دیگر <one_to_many> در Department.hbm.xml است.
نوبت به professor میرسد که از همه جالبتر است، زیرا هم از interface ای بنام person به ارث رفته و هم یک جدول مشترک با دانشجو دارد. برای تشخیص professor و student باید به NH بگوییم که نوع موجودیت چیست و در <discriminator> آن را مشخص میکنیم.
اگر نگاهی به مدل بیاندازید person ،3 فیلد را مشخص میکند: id ، person و lastname. student و professor هر دو این نمایندهٔ این فیلدها هستند اما آنه اتفاوت دارند. Student ، ssn دارد در حالی که professor ، identifier دارد. Professor مجموعهای از دانشگاهها و کلاسها را دارد در حالی که student فقط مجموعهای از کلاسها (ی درس) را دارد. شما میتوانید فیلدها را در کلاس person مپ کنید اما فیلدهایی را که خاص هستند به عنوان subtype در <subclass> مپ کنید.
در حقیقت برای ثبت فضا، مجموعه مختلفی از فایلهای مپ شده را برای پررنگ کردن featureهای polymorphism related ادغام میکنیم. این مجموعه به نظر میرسد شبیه مثالهای بالا باشد.
<?xml version=«1.0« encoding=«utf-8« ?>
<hibernate-mapping xmlns=«urn:nhibernate-mapping-2.0«>
<class name=«nhRegistration.Person, nhRegistration« table=«People«>
<id name=«Id« column=«PersonID« type=«Int32«>
<generator class=«assigned« />
</id>
<discriminator column=«PersonType« type=«String«/>
<property name=«FirstName« column=«FirstName» type=«String(50)«/>
<property name=«LastName« column=«LastName» type=«String(50)«/>
<subclass name=«nhRegistration.Professor, nhRegistration» discriminator-value=«Professor«>
<property name=«Identifier« column=«Identifier» type=«String«/>
</subclass>
<subclass name=«nhRegistration.Student, nhRegistration» discriminator-value=«Student«>
<property name=«SSN« column=«Identifier» type=«String«/>
</subclass>
</class>
</hibernate-mapping>
با انجام کارهای بالا شما یک پروژه را با موفقیت به پایگاه داده مپ کردهاید. در مطالب بعدی نحوه استفاده از این کلاسها را مرور خواهیم کرد.
منابعی که در نگارش این مطلب بکار رفته است.

جالب بود ، موفق باشيد
سلام دوست عزيز
مطالبت فوق العاده بود و من خيلي كامل روند كار رو ياد گرفتم
فقط يك مطلبي؟
هيچ tools وجود ندارد كه بصورت اتوماتيك اين XMLMapp ها را بسازد؟؟!!!
Microsoft visio برات حتی اسکریپت های SQL رو هم میسازه
سلام
میگم شما قصد ازدواج ندارید؟