شبکه دی
بازدید: 1633
کد: 41
زمان انتشار: پنجشنبه 8 فروردین 1392

استفاده از کلاس های Entity Framework CodeFirst در WCF

استفاده از کلاس های Entity Framework CodeFirst در WCF

استفاده از کلاس های Entity Framework CodeFirst در WCF

مایکروسافت در نسخه Entity Framework 4.1 برای اولین بار کلاس DbContext را معرفی نمود که شیوه نوینی جهت برنامه نویسی برای پایگاه داده بوده و با نام CodeFirst شناخته می شود. این شیوه برنامه نویسی بسیار مورد استقبال برنامه نویسان گرفت و در نسخه های بعدی امکانات جالب فراوانی به آن اضافه شد و هم اکنون نیز در حال توسعه و بهینه سازی می باشد.

یکی از مشکلات کار با ابزار های ORM این است که کلاس های تولید شده معمولا از کلاس های پایه ای به ارث رفته اند و این موضوع باعث می شود که این کلاس ها به سادگی قابل انتقال از سمت سرویس به کلاینت نباشند و هزینه سریالایز (Serialize) و دی سریالایز (Deserialize) نمودن این کلاس ها نیز بسیار بالا است.

به همین دلیل این موضوع همواره مورد علاقه برنامه نویسان بوده است که بتوانند از کلاس های پایه خود (POCO) و بدون هیچ سربار اضافی به جای کلاس های پیشفرض تولید شده توسط Entity Framework استفاده نمایند.

با استفاده از روش CodeFirst براحتی می توان این قابلیت را ایجاد نمود. برای درک بهتر مسئله، به مثال زیر توجه کنید:

فرض کنید که دو کلاس به نام های Customer و Address داریم و به ازای این دو کلاس، دو جدول در پایگاه داده با همین نام ها وجود دارد. رابطه بین جدول Customer با جدول Address از نوع "یک به چند" می باشد یعنی هر مشتری می تواند چندین آدرس داشته باشد.

کلاس های مربوط به این جداول در روش CodeFirst مشابه قطعه کد زیر می باشند:

public partial class CustomerDBEntities : DbContext


{
public DbSet<Address> Addresses { get; set; }
public DbSet<Customer> Customers { get; set; }
}

public class Customer


{
public Customer()
{
this.Addresses = new HashSet<Address>();

}
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<Address> Addresses { get; set; }

}

public class Address


{
public int AddressId { get; set; }
public int CustomerId { get; set; }
public string Street { get; set; }
public string Alley { get; set; }
public int No { get; set; }
public Customer Customer { get; set; }
}

همانطور که در مثال بالا مشاهده می فرمایید، کلاس های Customer و Address از هیچ کلاس دیگری به ارث نرفته اند و دارای ویژگی های اضافه دیگری نیز نیستند و کاملا مناسب برای منظور ما یعنی استفاده در سرویس های WCF می باشند.

در ورش بالا چند محدودیت برای برنامه نویس ایجاد می شود، از جمله اینکه چون موجودیت ها از کلاس های پایه Entity Framework به ارث نرفته اند، پس قابلیت های Lazy Loading و Change Traking از کار افتاده اند و دیگر قابل استفاده نمی باشند.

برای اینکه قابلیت Lazy Loading را برای کلاس ها فراهم کنیم کافیست که خصوصیاتی ناوبری (Navigation Properties) را به شکل virtual در آوریم. لازم به ذکر است که خصوصیاتی ناوبری، همان خصوصیاتی می باشند که نمایانگر ارتباط بین کلاس ها (و احتمالا جداول پایگاه داده) می باشند. در مثال ما هر مشتری می تواند چندین آدرس داشته باشد و هر آدرس حتما مربوط به یک مشتری می باشد. بنابراین خصوصیت Addresses در کلاس Customer و خصوصیت Customer در کلاس Address نمایانگر این رابطه بوده و خصوصیاتی ناوبری می باشند.

تغییرات ما برای کلاس های Customer و Address به شکل زیر اعمال شده است.

public class Customer


{ public Customer()
{
this.Addresses = new HashSet<Address>();
}
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Vritual ICollection<Address> Addresses { get; set; }

}

public class Address


{
public int AddressId { get; set; }
public int CustomerId { get; set; }
public string Street { get; set; }
public string Alley { get; set; }
public int No { get; set; }
public virtual Customer Customer { get; set; }
}

شاید این سوال در ذهنتان بوجود آمده باشد که چگونه فقط با اضافه نموده کلمه کلیدی virtual این قابلیت Lazy Loading به کلاس های ما اضافه می شود؟!

با virtual نمودن خصوصیات ناوبری، Entity Framework هنگام اجرای برنامه (RunTime) کلاس هایی با عنوان "پروکسی های پویا" یا همان Dynamic Proxies به کلاس های Address و Customer اضافه می کند و بنابراین قابلیت Lazy Loading برای این کلاس ها در زمان اجرای برنامه فراهم می گردد.

تا اینجای کار توانستیم با تغییر کوچکی در کلاس ها قابلیت Lazy Loading را فراهم کنیم ولی با اضافه شدن پروکسی های پویا به کلاس های ما، مجددا مشکل ابتدای مقاله پدیدار می شوند و این کلاس ها قابلیت انتقال خود از طریق سرویس های WCF را از دست می دهند زیرا پروکسی های پویا به طور پیش فرض قابلیت سریالایز و دیسریالایز شدن را ندارند!

نکته:
قبل از این که به سراغ راه حل برویم بد نیست به این موضوع نیز اشاره کنیم که در صورتی که تمامی خصوصیات کلاس های خود را virtual کنیم، قابلیت Change Tracking نیز به کلاس های ما اضافه می شود ولی اضافه نمودن این قابلیت بر روی راندمان و کارایی برنامه تاثیر می گذارد.

خوشبختانه با استفاده کلاس DbContext می توانیم تولید کلاس های پروکسی را در زمان اجرای برنامه را فعال یا غیر فعال کنیم. بنابراین تنها کافیست که هر زمان نیاز به استفاده از آن ها در سرویس های WCF داشتیم، این قابلیت را به شکل زیر از کار بیندازیم. در اینصورت قابلیت Lazy Loading و برخی ویژگی های دیگر از کار افتاده و کلاس ها قابلیت استفاده در سرویس های WCF را خواهند داشت.


public Customer GetFirstCustomer()
{ using(var context = new CustomerDBEntities())
{
context.Configuration.ProxyCreationEnabled = false;
var firstCustomer = context.Customers.FirstOrDefault() return firstCustomer;
}
}

در متد بالا ویژگی ProxyCreationEnabled مربوط به کلاس DbContext را غیر فعال نموده ایم و بنابراین پروکسی های داینامیک تولید نخواهند شد و نتیجه کوئری قابل استفاده در سرویس های WCF خواهد بود.


نویسنده: مهندس صحراگرد
ویراستار: Admin
حق نشر برای شبکه دی محفوظ است 1392
Day Telecom © 2013


برای نمایش مقالات شما به نام خودتان در دانشنامه دی لطفا مطالب را به webmaster [at] day.ir ارسال بفرمایید.

منبع: سی شارپ دات کام
آخرین بروزرسانی: پنجشنبه 29 فروردین 1392 20:55:18
خانه | خدمات | محصولات | تماس با ما | درباره ما

تمامی حقوق مادی و معنوی این وب سایت برای شبکه دی محفوظ است.
© 2018 All Right Reserved DAY Telecom Group