استفاده از LINQ جهت انجام كوئريها توسط NHibernate
نگارش نهايي 1.0 كتابخانهي LINQ to NHibernate اخيرا (حدود سه ماه قبل) منتشر شده است. در اين قسمت قصد داريم با كمك اين كتابخانه، اعمال متداول انجام كوئريها را بر روي ديتابيس قسمت قبل انجام دهيم.
توسط اين نگارش ارائه شده، كليه اعمال قابل انجام با criteria API اين فريم ورك را ميتوان از طريق LINQ نيز انجام داد (NHibernate براي كار با دادهها و جستجوهاي پيشرفته بر روي آنها، HQL : Hibernate Query Language و Criteria API را سالها قبل توسعه داده است).
جهت دريافت پروايدر LINQ مخصوص NHibernate به آدرس زير مراجعه نمائيد:
پس از دريافت آن، به همان برنامه كنسول قسمت قبل، دو ارجاع را بايد افزود:
الف) ارجاعي به اسمبلي NHibernate.Linq.dll
ب) ارجاعي به اسمبلي استاندارد System.Data.Services.dll دات نت فريم ورك سه و نيم
در ابتداي متد Main برنامه قصد داريم تعدادي مشتري را به ديتابيس اضافه نمائيم. به همين منظور متد AddNewCustomers را به كلاس CDbOperations برنامه كنسول قسمت قبل اضافه نمائيد. اين متد ليستي از مشتريها را دريافت كرده و آنها را در طي يك تراكنش به ديتابيس اضافه ميكند:
public void AddNewCustomers(params Customer[] customers)
{
using (ISession session = _factory.OpenSession())
{
using (ITransaction transaction = session.BeginTransaction())
{
foreach (var data in customers)
session.Save(data);
session.Flush();
transaction.Commit();
}
}
}
پس از افزودن اين ارجاعات، كلاس جديدي را به نام CLinqTest به برنامه كنسول اضافه نمائيد. ساختار كلي اين كلاس كه قصد استفاده از پروايدر LINQ مخصوص NHibernate را دارد بايد به شكل زير باشد (به كلاس پايه NHibernateContext دقت نمائيد):
using System.Collections.Generic;
using System.Linq;
using NHibernate;
using NHibernate.Linq;
using NHSample1.Domain;
namespace ConsoleTestApplication
{
class CLinqTest : NHibernateContext
{ }
}
using System.Collections.Generic;
using System.Linq;
using NHibernate;
using NHibernate.Linq;
using NHSample1.Domain;
namespace ConsoleTestApplication
{
class CLinqTest : NHibernateContext
{
ISessionFactory _factory;
public CLinqTest(ISessionFactory factory)
{
_factory = factory;
}
public List<Customer> GetAllCustomers()
{
using (ISession session = _factory.OpenSession())
{
var query = from x in session.Linq<Customer>() select x;
return query.ToList();
}
}
}
}
در اين كوئري، ليست تمامي مشتريها بازگشت داده ميشود.
سپس جهت استفاده و بررسي آن در متد Main برنامه خواهيم داشت:
static void Main(string[] args)
{
using (ISessionFactory session = Config.CreateSessionFactory(
MsSqlConfiguration
.MsSql2008
.ConnectionString("Data Source=(local);Initial Catalog=HelloNHibernate;Integrated Security = true")
.ShowSql()
))
{
var customer1 = new Customer()
{
FirstName = "Vahid",
LastName = "Nasiri",
AddressLine1 = "Addr1",
AddressLine2 = "Addr2",
PostalCode = "1234",
City = "Tehran",
CountryCode = "IR"
};
var customer2 = new Customer()
{
FirstName = "Ali",
LastName = "Hasani",
AddressLine1 = "Addr..1",
AddressLine2 = "Addr..2",
PostalCode = "4321",
City = "Shiraz",
CountryCode = "IR"
};
var customer3 = new Customer()
{
FirstName = "Mohsen",
LastName = "Shams",
AddressLine1 = "Addr...1",
AddressLine2 = "Addr...2",
PostalCode = "5678",
City = "Ahwaz",
CountryCode = "IR"
};
CDbOperations db = new CDbOperations(session);
db.AddNewCustomers(customer1, customer2, customer3);
CLinqTest lt = new CLinqTest(session);
foreach (Customer customer in lt.GetAllCustomers())
{
Console.WriteLine("Customer: LastName = {0}", customer.LastName);
}
}
Console.WriteLine("Press a key...");
Console.ReadKey();
}
مهمترين مزيت استفاده از LINQ در اين نوع كوئريها نسبت به روشهاي ديگر، استفاده از كدهاي strongly typed دات نتي تحت نظر كامپايلر است، نسبت به رشتههاي معمولي SQL كه كامپايلر كنترلي را بر روي آنها نميتواند داشته باشد (براي مثال اگر نوع يك ستون تغيير كند يا نام آن، در حالت استفاده از LINQ بلافاصله يك خطا را از كامپايلر جهت تصحيح مشكلات دريافت خواهيم كرد كه اين مورد در زمان استفاده از يك رشته معمولي صادق نيست). همچنين مزيت فراهم بودن Intellisense را حين نوشتن كوئريهايي از اين دست نيز نميتوان نديد گرفت.
مثالي ديگر:
ليست تمام مشتريهاي شيرازي را نمايش دهيد:
ابتدا متد GetCustomersByCity را به كلاس CLinqTest فوق اضافه ميكنيم:
public List<Customer> GetCustomersByCity(string city)
{
using (ISession session = _factory.OpenSession())
{
var query = from x in session.Linq<Customer>()
where x.City == city
select x;
return query.ToList();
}
}
foreach (Customer customer in lt.GetCustomersByCity("Shiraz"))
{
Console.WriteLine("Customer: LastName = {0}", customer.LastName);
}
ليست كامل ديتابيسهاي پشتيباني شده توسط NHibernate را در اين آدرس ميتوانيد مشاهده نمائيد. (البته به نظر ليست آن، آنچنان هم به روز نيست؛ چون در نگارش آخر NHibernate ، پشتيباني از اس كيوال سرور 2008 هم اضافه شده است)
نكته:
در كوئريهاي مثالهاي فوق همواره بايد session.Linq<T> را ذكر كرد. اگر علاقمند بوديد شبيه به روشي كه در LINQ to SQL موجود است مثلا db.TableName بجاي session.Linq<T> در كوئريها ذكر گردد، ميتوان اصلاحاتي را به صورت زير اعمال كرد:
يك كلاس جديد را به نام SampleContext به برنامه كنسول جاري با محتويات زير اضافه نمائيد:
using System.Linq;
using NHibernate;
using NHibernate.Linq;
using NHSample1.Domain;
namespace ConsoleTestApplication
{
class SampleContext : NHibernateContext
{
public SampleContext(ISession session)
: base(session)
{ }
public IOrderedQueryable<Customer> Customers
{
get { return Session.Linq<Customer>(); }
}
public IOrderedQueryable<Employee> Employees
{
get { return Session.Linq<Employee>(); }
}
public IOrderedQueryable<Order> Orders
{
get { return Session.Linq<Order>(); }
}
public IOrderedQueryable<OrderItem> OrderItems
{
get { return Session.Linq<OrderItem>(); }
}
public IOrderedQueryable<Product> Products
{
get { return Session.Linq<Product>(); }
}
}
}
سپس بازنويسي متد GetCustomersByCity بر اساس SampleContext فوق به صورت زير خواهد بود كه به كوئريهاي LINQ to SQL بسيار شبيه است:
using System.Collections.Generic;
using System.Linq;
using NHibernate;
using NHSample1.Domain;
namespace ConsoleTestApplication
{
class CSampleContextTest
{
ISessionFactory _factory;
public CSampleContextTest(ISessionFactory factory)
{
_factory = factory;
}
public List<Customer> GetCustomersByCity(string city)
{
using (ISession session = _factory.OpenSession())
{
using (SampleContext db = new SampleContext(session))
{
var query = from x in db.Customers
where x.City == city
select x;
return query.ToList();
}
}
}
}
}
و در تكميل اين بحث، ميتوان به ليستي از 101 مثال LINQ ارائه شده در MSDN اشاره كرد كه يكي از بهترين و سريع ترين مراجع يادگيري مبحث LINQ است.
ادامه دارد ...