شروع کار با Fluent NHibernate با یک نمونه کد

دسامبر 8, 2009 5 دیدگاه

اگر Fluent NHibernate را downdoad کرده‌اید آنرا اجرا کنید. وگر نه با استفاده از این لینک آن را دانلود کنید.

در این مثال ما یک domain ساده را برای یک کمپانی خرده‌فروشی در نظرگرفته‌ایم. فروشگاه کارمند و کالا دارد که هر کدام با یکدیگر ارتباط دارند. برای روشن شدن مسئله شکل زیر را ملاحظه کنید.

ابتدا یک console Application ایجاد کنید و fluent NHibernate.dll را به آن ارجاع دهید. و هر کدام از نسخه‌های NHibernate را که تمایل داشتید در آن قرار دهید. برای این مثال ما از دیتابیس SQLite استفاده می‌کنیم. همچنین شما به کتابخانهٔ  System.Data.SQLite که با fluent NHibernate ساخته شده است نیز نیاز دارید.

شما می‌توانید ساختار پروژه را در شکل روبرو ببینید. پوشهٔ Entities بخش واقعی آبجکت‌هاست و پوشهٔ mappings محل قرارگیری کلاس‌های mapping شما است.

پوشه Enteties :

اجازه دهید با ساخت entity ها شروع کنیم. ما سه جدول داریم که با هم ارتباط دارند و باید مپ شوند. برای هر کدام، کلاسی جداگانه و مخصوص به خود را در پوشهٔ Enteties می‌سازیم.

ابتدا با کلاس employee کارمان را آغاز می‌کنیم.

public class Employee
{
public virtual int Id { get; private set; }
public virtual string FirstName { get; set;}
public virtual string LastName { get; set; }
public virtual Store Store { get; set; }
}

همانطور که ملاحظه می‌کنید به ازای تمام فیلدهای جدول موجود در پایگاه داده، در این فایل یک صفت (property) داریم.

اگر شما با NHibernate ناآشنا هستید باید بدانید که دو چیز مهم و برجسته در اینجا وجود دارد. اول اینکه مشخصهٔ id به صورت private ، set شده است و این به این خاطر است که فقط NHibernate است که می‌تواند این مقدار را set کند. دوم اینکه همهٔ property ها virtual هستند، بخاطر اینکه NHibernate در حین اجرا از موجودیت‌ها proxy هایی می‌سازد که اجازه می‌دهد Lazy load باشد، یعنی اینکه قابلیت override را برای property ها داشته باشد.

دو کلاس دیگر را هم به صورت زیر می‌سازیم. (توجه کنید که به ازای فیلدهای جدول خودشان و با Type های صحیح اقدام به ایجاد صفت کنید، درغیر این صورت شما با مشکل روبرو خواهید شد. )

پیاده سازی کلاس محصول

public class Product
{
 public virtual int Id { get; private set; }
 public virtual string Name { get; set; }
 public virtual double Price { get; set; }
 public virtual IList<Store> StoresStockedIn { get; private set;{
 public Product()   //constructor
 {
 StoresStockedIn = new List<Store>();
 }
}
public class Store
{
 public virtual int Id { get; private set; }
 public virtual string Name { get; set; }
 public virtual IList<Product> Products { get; set; }
 public virtual IList<Employee> Staff { get; set; }
<pre>

پیاده سازی کلاس خرده‌فروشی (مغازه)


</pre>
public Store()
 {
 Products = new List<Product>();
 Staff = new List<Employee>();
 }
public virtual void AddProduct(Product product)
 {
 product.StoresStockedIn.Add(this);
 Products.Add(product);
 }

 public virtual void AddEmployee(Employee employee)
 {
 employee.Store = this;
 Staff.Add(employee);
 }
}

متدهای add employee و add product کمی به ساده‌تر شددن کد ما کمک می‌کنند. این متدها برای اضافه کردن یک item به collection و تنظیم کردن سمت دیگر رابطه استفاده می‌شوند. (برای اضافه کردن کالا و کارمند به فروشگاه)
پوشه Mappings :
حالا که entity ها را ساختیم وقت آن رسیده که آنها را با استفاده از fluent NHibernate مپ کنیم. با یک کلاس ساده مثل employee شروع می‌کنیم. Mapper های زیر باید در پوشهٔ mappings ساخته شوند.
برای مپ کردن هر entity شما باید یک کلاس مپ اختصاصی برایش ایجاد کنید. این کلاس مپینگ‌ها از ClassMapp<T> به ارث می‌روند و T ، درواقع نام entity ی ورودی شما است.

public class EmployeeMap : ClassMap<Employee>
{
 public EmployeeMap()
 {
 Id(x => x.Id);
 Map(x => x.FirstName);
 Map(x => x.LastName);
 References(x => x.Store);
 }
}

ستون id یک شناسه برای fluent NHibernate است و x مثالی از یک نمونه از employee است که fluent NHibernate از آن برای بدست آوردن جزئیات property ها استفاده می‌کند.

public class StoreMap : ClassMap<Store>
{
 public StoreMap()
 {
 Id(x => x.Id);
 Map(x => x.Name);
 HasMany(x => x.Staff).Inverse().Cascade.All();
 HasManyToMany(x => x.Products).Cascade.All().WithTableName("StoreProduct");
 }
}

همان طور که ملاحضه می‌کنید در اینجا فراخوان‌های دیگری نیز به چشم می‌خورد. اگر employee را بخاطر بیاورید در آنجا یک ارتباط یک به چند با store داشتیم. حالا هم در مپ کردن store باید این ارتباط را نیز در نظر بگیریم. HasMany یک ارتباط یک به چند را با employee برقرار می‌کند. در اینجا یک متد جدید HasManyToMany وجود دارد که ارتباط چند به چند با product را ایجاد می‌نماید.
Inverse در HasMany یک عبارت (کلمه کلیدی) در NHibernate است و در پایان ارتباط مسئولیت save را به عهده دارد.
CascadeAll در HasManyToMany به NHibernate می‌گوید که در سلسلهٔ آبشاری عمل save را انجام دهد.
WithTableName نام طرف دیگر ارتباط را در چند به چند مشخص می‌کند. برای سایر ارتباطات به وجود این قسمت نیاز نمی‌باشد.

public class ProductMap : ClassMap<Product>
{
 public ProductMap()
 {
 Id(x => x.Id);
 Map(x => x.Name);
 Map(x => x.Price);
 HasManyToMany(x => x.StoresStockedIn).Cascade.All().Inverse().WithTableName("StoreProduct");
 }
}

Application :
در این بخش data ها مقداردهی اولیه می‌شوند.

static void Main()
{
 var sessionFactory = CreateSessionFactory();

 using (var session = sessionFactory.OpenSession())
 {
 using (var transaction = session.BeginTransaction())
 {
 // create a couple of Stores each with some Products and Employees
 var barginBasin = new Store { Name = "Bargin Basin" };
 var superMart = new Store { Name = "SuperMart" };

 var potatoes = new Product { Name = "Potatoes", Price = 3.60 };
 var fish = new Product { Name = "Fish", Price = 4.49 };
 var milk = new Product { Name = "Milk", Price = 0.79 };
 var bread = new Product { Name = "Bread", Price = 1.29 };
 var cheese = new Product { Name = "Cheese", Price = 2.10 };
 var waffles = new Product { Name = "Waffles", Price = 2.41 };

 var daisy = new Employee { FirstName = "Daisy", LastName = "Harrison" };
 var jack = new Employee { FirstName = "Jack", LastName = "Torrance" };
 var sue = new Employee { FirstName = "Sue", LastName = "Walkters" };
 var bill = new Employee { FirstName = "Bill", LastName = "Taft" };
 var joan = new Employee { FirstName = "Joan", LastName = "Pope" };

 // add products to the stores, there's some crossover in the products in each
 // store, because the store-product relationship is many-to-many
 AddProductsToStore(barginBasin, potatoes, fish, milk, bread, cheese);
 AddProductsToStore(superMart, bread, cheese, waffles);

 // add employees to the stores, this relationship is a one-to-many, so one
 // employee can only work at one store at a time
 AddEmployeesToStore(barginBasin, daisy, jack, sue);
 AddEmployeesToStore(superMart, bill, joan);

 // save both stores, this saves everything else via cascading
 session.SaveOrUpdate(barginBasin);
 session.SaveOrUpdate(superMart);

 transaction.Commit();
 }

 // retreive all stores and display them
 using (session.BeginTransaction())
 {
 var stores = session.CreateCriteria(typeof(Store))
 .List<Store>();

 foreach (var store in stores)
 {
 WriteStorePretty(store);
 }
 }

 Console.ReadKey();
 }
}

public static void AddProductToStore(Store store, params Product[] products)
{
 foreach (var product in products)
 {
 store.AddProduct(product);
 }
}

public static void AddEmployeeToStore(Store store, params Employee[] employees)
{
 foreach (var employee in employees)
 {
 store.AddEmployee(employee);
 }
}

اما شما الان قادر به run  کردن برنامه نیستید زیرا ما نیاز داریم متد CreateSessionFactory را پیاده سازی کنیم.

private static ISessionFactory CreateSessionFactory()
{
 return Fluently.Configure()
.Database(
 SQLiteConfiguration.Standard
 .UsingFile("firstProject.db")
 )
 .Mappings(m =>
 m.FluentMappings.AddFromAssemblyOf<Program>())
 .BuildSessionFactory();
}

اگر شما برای برنامه نمی‌خواهید که Schema را دستی تهیه کنید، اجرای دفعهٔ اول fail می‌شود. و آن به این خاطر است که یک چیز دیگر در آبجکت NHibernate configuration نیاز دارید و آن متد expose configuration  است . با استفاده از آن شما قادرید در زمان اجرا (Run Time) Schema را بسازید. (اگر مایلید که این کار را انجام دهید) کد را به صورت زیر تغییر بدهید.

private static ISessionFactory CreateSessionFactory()
{
 return Fluently.Configure()
 .Database(
 SQLiteConfiguration.Standard
 .UsingFile("firstProject.db")
 )
 .Mappings(m =>
 m.FluentMappings.AddFromAssemblyOf<Program>())
 .ExposeConfiguration(BuildSchema)
 .BuildSessionFactory();
}

private static void BuildSchema(Configuration config)
{
 // delete the existing db on each run
 if (File.Exists(DbFile))
 File.Delete(DbFile);
 // this NHibernate tool takes a configuration (with mapping info in)
 // and exports a database schema from it
 new SchemaExport(config)
 .Create(false, true);
}

با استفاده از کد بالا Schema شما بصورت RunTime ایجاد می‌شود و شما لازم نیست که بصورت دستی Schema را ایجاد نمایید.
شما میتوانید نمونه‌های بیشتری از fluent configuration  را در این لینک مشاهده کنید.
لینک‌های استفاده شده برای تهیهٔ این مطلب :
http://wiki.fluentnhibernate.org/show/HomePage
http://wiki.fluentnhibernate.org/show/GettingStarted:+First+Project
http://wiki.fluentnhibernate.org/show/FluentConfiguration

دسته‌ها:Programming

Fluent NHibernate چیست؟

ژوئیه 30, 2009 ۱ دیدگاه

Fluent NHibernate Logo

Fluent NHibernate Logo

Fluent NHibernate نیز مانند NHibernate یک برنامۀ open source است که برای map کردن کلاس ها به جداول database مورد استفاده قرار می‌گیرد.

FluentNHibernate پیشنهاد می‌کندکه بجای نوشتن کد xml تحت عنوان (.hbm.xml files) از کدC# استفاده کنید.این باعث می‌شود کدنویسی ساده‌تر شده و قابلیت خواندن کدها بهبود یابد و البته کد کوتاه‌تر شود.

همانطور که می‌دانید در استفاده از NHibernate به عنوان یک OR Mapper برای مپ کردن کلاسها به جداول از فایل‌های xml استفاده می‌شود.اما Fluent NHibernate چیز دیگری را پیشنهاد می‌کند.اما چرا؟

فایل xml خوب است اما چند مورد نامطلوب در مورد آن وجود دارد:

  1. به علت اینکه xml بوسیله‌ٔ کامپایلر ارزیابی نمی‌شود‌،شما می‌توانید در کلاسهایتان نام property ها را تغییر دهید ولی آنها در فایل‌های mapping ، update نمی‌شوند. و شما این تغییر را تا زمان اجرا متوجه نمی‌شوید.
  2. فایل xml زیادی طولانی است.گرچه NHibernate به تدریج از element های اجباریxml کاسته اما شما هنوز از این درازنویسی رها نشده‌اید.
  3. Mapping های تکراری-فایل‌های hbm در NHibernate می‌توانند کاملاً طولانی شوند اگر شما برای هر یک قوانینی تعین کنید.مثل اینکه بخواهید همهٔ string ها not-null باشند.

حالا Fluent NHibernate چگونه با این مسا‌ئل برخورد می‌کند:

می‌توانید mapping هاتان را به سمت کد واقعی حرکت دهید پس آنها در تمام application کامپایل می‌شوند و اگر تغییراتی را اعمال کنید کامپایلر در لحظه اخطار می‌دهد و یا با refactory تغییرات را اعمال می‌کند. و برای بازنویسی قوانین نحوه‌ای را پیشنهاد می‌کند که یک بار این قوانین نوشته شوند.

به نمونه کد زیر توجه کنید.

public class CatMap : ClassMap
{
public CatMap()
{
Id(x => x.Id);
Map(x => x.Name).WithLengthOf(16).Not.Nullable();
Map(x => x.Sex);
References(x => x.Mate);
HasMany(x => x.Kittens);
}
}

Fluent NHibernate را می‌توانید از سایت رسمی‌اش به این آدرس

و یا از سرورهای گوگل کد در این آدرس دریافت نمایید.

دسته‌ها:Programming برچسب‌ها: , , ,

NHibernate 2.1 عرضه شد

ژوئیه 26, 2009 2 دیدگاه

همانطور که می‌دانید دیروز یعنی در مورخهٔ 2009/25/7 ورژن 2.1 ، NHibernate  عرضه شد. در صورت تمایل می‌توانید از این لینک برای Download استفاده کنید.

اگر شما تا حالا با NHibernate 2.0 کار می‌کردید و حالا می‌خواهید آن را به نسخه جدید upgrade  کنید. اگر برای این کار فقط فایل‌های dll را تغییر دهید و برنامه را اجرا کنید به error زیر برمی‌خورید.

The ProxyFactoryFactory was not configured.

برای رفع این مشکل باید صفت ‘proxyfactory.factory_class’ را از بخش session-factory   در Web.Config برنامه با یک NHibernate.ByteCode مقدار دهی اولیه کنید.

برای این کار به روش زیر عمل کنید:

فایل Web.Config را باز کرده

بخش مربوط به NHibernate را در آن پیدا کنید و صفت زیر را به آن اضافه کنید.

<property name=’proxyfactory.factory_class’>NHibernate.ByteCode.LinFu.ProxyFactoryFactory, NHibernate.ByteCode.LinFu</property>

همچنین می‌توانید بصورت زیر نیز عمل کنید:

<property name=’proxyfactory.factory_class’>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>

همانطور که ملاحظه کردید . پیش از این NHibernate  بطور پیش فرض از Castles Dynamic proxy برای generate ، proxy های runtime استفاده می‌کرد اما در نسخه جدید شما می‌توانید از هر نمونه دلخواهی استفاده کنید و به همین دلیل باید آن را در تنظیمات برنامه اضافه کنید.

<property name=»proxyfactory.factory_class»>NHibernate.ByteCode.Castle.ProxyFactoryFactory, NHibernate.ByteCode.Castle</property>

اگر هم می‌خواهید از proxy factory دیگری استفاده کنید، دقت کنید که آن را به صورت صحیح اضافه کنید.

لینک‌های مرتبط و منابع

دانلود فایلها و سورس Nhibernate از سرور SourceForge

رفع مشکل بروزرسانی NHibernate از نسخه ۲.۰ به نسخه ۲.۱

ساخت، load و ذخیره کردن آبجکت‌ها در NHibernate

ژوئیه 7, 2009 بیان دیدگاه
از آنجایی که هدف از session فراهم کردن مکانیزمی برای مدیریت کارایی برنامۀ شماست و در حقیقت این مدیریت برای پیشگیری از round trip ها در DataBase است، منطقی است که عملیات روی session همیشه نتیجۀ عملیات زیرساختی DataBase نیست (نباشد). در حقیقت آن یک اشاره‌گر به session برای cache کردن عملیات است تا اینکه آنها بتوانند در دیتابیس ذخیره شوند، بدینگونه round trip ها ذخیره می شوند. همۀ اینها بدین معنی است که وقتی که شما یک متد پایدار را در session صدا می کنید، با تغییرات آنی در database ممکن است که جواب بدهد یا ندهد.
معمولا تغییرات فقط هنگامی در دیتابیس ذخیره می شوند که متد session’s flush() صدا زده شوند.شما می توانید مستقیما این را انجام دهید.اما بیشتر رایج است که flush() را در پایان عملیات صدا کنیم.
اگر شما یک برنامۀ دیتابیسی ساخته باشید اما به این تراکنش‌ها علاقمند نباشید، باید زمانی را به بهبود طرحتان اختصاص دهید. لازم است که وقتی که حتی Query‌ها را دستی می‌نویسید مطمئن باشید که واحد اتمیک تغییرات را به دیتابیس اعمال می کند. این قضیه اهمیت بیشتری پیدا می کند وقتی که از لایۀ ORM ی مانند NHibernate استفاده می شود. زیرا یک دستورالعمل ساده مانند save(dept) می‌تواند تغییر حاصله را در چندین بخش از دیتابیس مانند professor ،classes و یا روی join table ها اعمال کند. اگر هر کدام از این تغییرات fail شود و شما هیچ مدیریتی بر آنچه که می‌نویسید نداشته باشید، دیتابیس شما بلااستفاده رها خواهد شد. بنابراین زمانی که از NHibernate استفاده می کنید از session ها بدون تراکنش استفاده نکنید. الگوی استفاده رایج به این صورت می‌باشد:

ISession session;
ITransaction tx;
try
}
session = factory.OpenSession();
tx = session.BeginTransaction();
// do database work
tx.Commit();
session.Close();
{
catch (Exception ex(
}
tx.Rollback();
session.Close();
// further exception handling
{

نویسندگان مستندات Hibernate مصرانه پیشنهاد می‌کنند که هرگز یک exception را بازیابی نکنید زیرا بازیابی تراکنش به عنوان اولین قدم در handle کردن Exception ها در ابتدای برنامه قرار دارند. این خیلی مهم است زیرا NHibernate به صورت آبشاری مدیریت می کند.
جایی که به مشکل بخورند خودشان را نشان می‌دهند. بهترین نظر این است که همه چیز را به حالت اول برگردانید، در دامنه مدلتان مشکل را حل کنید و دوباره سعی کنید.
بگذارید راجع به انواع رایج فعالیت‌ها برای object های ماندگارمان صحبت کنیم. خب، دیدید که پیاده‌سازی سه متد اول interface DBMgr در بالا نمایش داده شد.متد getDepartments() لیستی از بخش های ِDepartment را برمی گرداند.

public IList getDepartments()
{
IList depts = null;
try
{
ISession session = factory.OpenSession();
ITransaction tx = session.BeginTransaction();
depts = session.CreateCriteria(typeof(Department)).List();
session.Close();
}
catch (Exception ex)
{
tx.Rollback();
session.Close();
// handle exception.
}
return depts;
}

آبجکت session نشان می‌دهد متد createcriteria() که به عنوان آرگومان، یک نوع کلاس پایدار را می‌گیرد. این نشان می‌دهد که NHibernate با تبدیل های مپ شده به آبجکت ها فعل و انفعال‌ها را تندتر می‌کند. در نتیجه list() نتایج برگشتی از تمامی interface های موجود را برمی‌گرداند. در این مورد بهتر است یک لیست شامل خواصی از Department را برگردانیم.که با دیتابیس کاملا یکی است (شامل تمام دیگر آبجکت های مرتبط با department). این متد صریحی است که استفاده می‌شود که در دیتابیس شما در میان تمام interface های کلاس تکرار می‌شود.
اگر شما می خواهید interface مشخصی از database را تکرار کنید شما باید مقادیر مشخص از شناسه فیلدها را برای کلاس هدف بدانید که شما دنبال آن هستید.

public Department getDepartment(int i)
{
Department d = null;
try
{
ISession session = factory.OpenSession();
ITransaction tx = session.BeginTransaction();
d = (Department)session.Load(typeof(nhRegistration.Department), i);
session.Close();
}
catch (Exception ex)
{
tx.Rollback();
session.Close();
// handle exception. }
return d;
}

فقط به خاطر داشته باشید که نتایج session.load() را به یک نوع مناسب object ای که برمی‌گرداند cast کنید.
در پایان آیا می‌خواهید تغییرات را در یک interface ذخیره کنید (یا یک interface جدید ایجاد کنید)؟ آیا session در متد برای شما session.save() را که برای ایجاد یک interface جدید به کار می‌رود در نظر گرفته است یا session update() که برای تغییر یک interface از session موجود به کار می رود؟ شما مجبورید که این دو را جدا در نظر بگیرید. اگر شما یک متد اشتباه را اجراکنید. تداخل session و خطاهای پایگاه داده رخ می‌دهد ، در interface ما با وجود اینکه پیاده‌سازی DBmgr فقط یک متد saveDepartment(Department dept) را دارد. این برای یک برنامۀ ساده عقلانی نیست که برنامه نویسان مجبور شوند بین ماندگار کردن یک object جدید و یک object از پیش موجود تفاوت قایل شوند به همین دلیل interface ما فقط یک متد دارد. در پیاده‌سازی ما هنوز نیازمند این تفلوت قایل شدن هستیم.

public void saveDepartment(Department dept)
{
try
{
ISession session = factory.OpenSession();
ITransaction tx = session.BeginTransaction();if(dept.Id == 0)
{
session.Save(dept);
}
else
{
session.Update(dept);
}
tx.Commit();
session.Close();
}
catch (Exception ex)
{
tx.Rollback();
session.Close();
// handle exception
}
}

ابتدا پیش از آنکه interface را ماندگار کنیم باید این را تشخیص دهیم که آیا از پیش وجود دارد یا اینکه جدید است. بوسیلۀ یک فیلد ساده تشخیص هویت integer ی، ما فقط ارزیابی می‌کنیم که مقدار آن صفر است یا نه. که این معنی را می‌دهد که هیچ ردیفی از قبل در پایگاه داده وجود ندارد. (صفت ثبت نشده را در بالا به یاد بیاورید). شما می‌توانید تصور کنید که این منطق، کاربردی در تشخیص هویت‌های پیچیده ندارد، هنگامی‌که ما در مورد از پیش وجود داشتن interface تصمیم‌گیری می‌کنیم، متد جدیدی را در session برای این کار در نظر می‌گیریم.

دسته‌ها:Programming برچسب‌ها: , , , , , , , , ,

پیاده سازی و پیکربندی NHibernate (با یک نمونه)

مارس 16, 2009 4 دیدگاه
در مطالب قبلی با مفهوم و کارایی ORMapper آشنا شدیم و سپس به معرفی NHibernate پرداختیم، در این مطلب قصد داریم تا با استفاده از یک مثال، بطور عملی یک پروژه را توسط NHibernate به Database پیوند دهیم. پس از انجام مراحل زیر شما بصورت عملی یک سیستم را با استفاده از NHibernate پیاده‌سازی کرده‌اید. لازم بذکر است که این مثال از سایت theserverside.net اقتباس شده است که با استفاده از این لینک می‌توانید اصل مطلب را ملاحظه کنید.
تمرین شماره یک : پیاده‌سازی عملی NHibernate

اهداف:

1. ایجاد فایل mapper

2. مشخص کردن primary key و identifier ها در فایل‌های مپر
3. ایجاد رابطه یک به چند در فایل‌های مپر ان.هایبرنیت
4. ایجاد رابطه چند به چند در فایل‌های مپر ان.هایبرنیت
5. ایجاد زیرکلاس در فایل‌های مپر
این مثال شامل یک سیستم داشجویی است که دربرگیرنده بخش‌های زیر است:
Department
University
Professor
Student

که ارتباطاتشان به صورت زیر تعریف شده است :

تمرین یک : روابط بین کلاس‌ها

تمرین یک : روابط بین کلاس‌ها

توضیحات :
یک دانشگاه دارای یک یا چند استاد است و یک استاد در یک یا چند دانشگاه مشغول به کار است، یک دانشگاه یک یا چند کلاس دارد و کلاس‌ها متعلق به یک دانشگاه هستند ، کلاس را یک استاد اداره می‌کند و هر استاد می‌تواند چند کلاس را اداره کند ، دانشجویان می‌توانند یک یا چند کلاس داشته باشند و هر کلاس می‌تواند یک یا چند دانشجو داشته باشد .
تعریف کلاس‌ها به صورت زیر می‌باشد :

public class Department
{
private int id;
private string name;
private IDictionary classes;
private IDictionary professors;
}
public class Professor : Person
{
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;
}

و نهایتا ساختار Database بدین شکل خواهد بود:
تمرین یک : روابط بین جداول پایگاه داده

تمرین یک : روابط بین جداول پایگاه داده

فایل‌های map شده

مرحلهٔ بعد فراهم کردن فایل‌های مپ شده است که با اطلاعات موجود در جداول در ارتباط هستند. هر کلاس، فایل‌های مپ شدهٔ خود را نیاز دارد. این فایل‌ها می‌توانند هرجا که شما بخواهید ذخیره شوند. اما بهتر است برای سادگی کار یک library به پروژه add کنید و این فایل‌ها را در آنجا ذخیره کنید. توجه داشته باشید که فایل‌های مپ شده برای ویژگی‌هایی که قرار است ماندگار (Persistence) باشند (ذخیره شوند) تهیه می‌شوند.

گام نخست: ایجاد جداول در پایگاه داده
برای شروع کار ابتدا در DataBase، جداول مربوطه را تشکیل می‌دهیم. (درست مانند شکل بالا، به این معنی که باتوجه به تصویر جداول پایگاه داده، این جداول را در Database ایجاد کنید).
گام دوم: ایجاد فایل‌های Map
س‍پس اقدام به ایجاد فایل‌های مپ شده می‌کنیم. (توجه داشده باشید که این کلاس‌ها باید با پسوند .xml ذخیره شوند). برای مثال باتوجه به موارد بالا، اگر بخواهیم برای کلاس Department فایل مپ ایجاد کنیم، باید بصورت زیر عمل کنیم. بدین منظور ابتدا تگ شناسایی xml را در ابتدای فایل بصورت زیر قرار می‌دهیم.

<?xml version=«1.0« encoding=«utf-8« ?>

بعد باید مشخص کنیم که این فایل یک فایل مپ شده برای NHibernate است. بدین منظور به شکل زیر NameSpace مورد استفاده را به فایل اضافه می‌کنیم.
<!–[if gte mso 9]> Normal 0 false false false EN-US X-NONE AR-SA <![endif]–><!–[if gte mso 9]> <![endif]–>

<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>

حالا کد ما به این شکل درآمده:

<!–[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.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 تفاوت می‌کند.

<!–[if gte mso 9]> Normal 0 false false false EN-US X-NONE AR-SA <![endif]–><!–[if gte mso 9]> <![endif]–><!–[endif]–>

<set name=«Professors« table=«departmentprofessor«>

<key column=«DeptID«/>

<many-to-many class=«nhRegistration.Person,nhRegistration» column=«Personid«/>

</set>

حال مپینگ کامل زیر را بخوانید

<!–[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.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>

با انجام کارهای بالا شما یک پروژه را با موفقیت به پایگاه داده مپ کرده‌اید. در مطالب بعدی نحوه استفاده از این کلاس‌ها را مرور خواهیم کرد.
منابعی که در نگارش این مطلب بکار رفته است.

نصب و راه اندازی NHibernate

مارس 11, 2009 2 دیدگاه

برای استفاده از NHibernate مراحل مخنلفی را باید سپری کرد که در زیر به آنها اشاره می‌شود. توجه داشته باشید که برای استفاده از ان.هایبرنیت باید کارهای دیگری انجام داد که در آینده به آنها خواهیم پرداخت، در این مطلب قصد داریم نحوه نصب و پیکربندی NHibernate را در یک سیستم تشریح کنیم .

گام اول . دانلود و نصب ان.هایبرنیت .

در ابتدا NHibernate را از اینجا در سورس فورگ دانلود کزده و نصب کنید.

گام دوم . اضافه کردن DLL های ان.هایبرنیت به پروژه.

پروژه‌ای ایجاد کنید و فایل اسمبلی داخل پوشه BIN را که از آدرس بالا دانلود کردید به پروژه اضافه کنید.

گام سوم . تنظیمات مورد نیاز در Web.Config .

در ادامه تنظیمات زیر در فایل web.config برنامه اضافه می‌کنیم.

<configuration>

<configSections>

<section name=«nhibernate« type=«System.Configuration.NameValueSectionHandler, System,Version=2.0.1,Culture=neutral,PublicKeyToken=b77a5c561934e089« />

</configSections>

<nhibernate>

<add key=«hibernate.connection.provider« value=«NHibernate.Connection.DriverConnectionProvider«/>

<add key=«hibernate.dialect« value=«NHibernate.Dialect.MsSql2000Dialect«/>

<add key=«hibernate.connection.driver_class« value=«NHibernate.Driver.SqlClientDriver«/>

<add key=«hibernate.connection.connection_string« value=«Server=.;initial catalog=nhibernate;UserID=sa;Password=123;Min Pool Size=2«/>

</nhibernate>

</configuration>

چند نکته که باید در ادامه به آنها توجه داشت.

وقتی برای تشخیص Data Store ، FrameWork تان را پیکربندی کردید، باید فضای مدل (ModelSpace) و همچنین پایگاه داده‌تان را معرفی و مشخص کنید.

نکته دیگری هم وجود دارد و آن map کردن فایل‌ها و توضیح روابط (Relations) بین کلاس‌ها و جداول است.

‫امروزه NHibernate ابزاری را فراهم کرده که می‌تواند DLL هایی را از فایل‌های map شده تولید کند. و اضافه کردن یک شیء جدید به برنامه، درواقع یک NAnt task است که بطور خودکار توسط ‏‏ #C از فایل‌های مپ شده تولید می‌شود.

با انجام تنظیمات بالا باید براحتی از NHibernate در برنامه‌تان استفاده کنید. در مطلب بعدی یک مثال کاملا عملی برای کار با NHibernate می‌آورم.

منابعی که برای نگارش این مطلب از آنها استفاده شده است

The Server Side .net

NHibernate on SourceForge

دسته‌ها:Programming, معرفی برچسب‌ها: , ,

ویژگی‌های NHibernate

فوریه 23, 2009 بیان دیدگاه

از آنجا که برای شروع به کار با یک برنامه، کسب اطلاع از نقاط ضعف و قوت آن از ملزومات است و از آنجا که برنامه NHibernate در یکی از حساس ترین و مهمترین لایه های برنامه نهایی اجرا می شود، دانستن مطالب زیر را الزامی می‌دانم، همچنین لازم بذکر است که مطالب زیر شامل مباحث فنی مختلفی است که از حوصله این مطلب خارج است به همین دلیل توضیحات مربوط به اصطلاحات ذکر شده را به عهده خواننده مطلب می‌گذارم.

1.     Natural programming model : بدین معنا که NHibernate ، OO را پشتیبانی می‌کند . یعنی ارث‌بری (Inheritance) ، چند‌ریختی (Polymorphism) ، ترکیب (Composition) ، Collection در .NET که شامل Generic collection ها هم می‌شود .

2.     Native .net ‏: API های NHibernate بر مبنای زبان‌های .NET و استانداردهای آن ایجاد شده است .

3.     Support for fine-grained object models : پشتیبانی از مدل‌های آبجکتی، از طریق مدل‌های مختلف غنی شده از مپینگ‌ها، برای Collection ها و Object  های وابسته .

4.     No build time byte code enhancement : در روند بیلد شدن، پردازش بر اساس بایت‌کدها و ایحاد کدهای اضافی وحود ندارد . در حقیقت در زمان بیلد شدن هیچ بهبودی در بایت‌کدها داده نمی‌شود .

5.     The query options : از بدست آوردن آبجکت‌های دیتابیس گرفته تا بدست آوردن خروجی‌های آنها . به هر دوی این مسائل می‌پردازد .

6.     Custom SQL : تصحیح کامل SQL که NHibernate باید برای آبحکت‌هایش از آنها استفاده کند .

7.     Support for “conversations” : ان.هایبرنیت از ماندگاری بالای مفاهیم ، سوا و سر‌هم‌بندی آبحکت‌ها پشتیبانی می‌کند و همچنین از optimistic locking به صورت خودکار مراقبت می‌کند .

8.     Free/open source : ان هاببرنیت، تحت مجوز LGPL (Lesser GNU Public License) است و سورس پروژه ان.هایبرنیت را از سایت SourceForge از اینجا می توانید دانلود کنید .

منابعی که در نگارش این مطلب از آنها استفاده شده است
     سایت رسمی NHibernate
     توضیحات ویکی پدیا در مورد NHibernate

دسته‌ها:معرفی برچسب‌ها: , ,