در قسمت قبل با نحوه اجرای پرس و جو آشنا شدید و همچنین به بررسی متدهای Find و Single و First و تفاوتهای آنها پرداختیم. در این قسمت با خصوصیت Local و متد Load آشنا خواهیم شد. همانطور که در قسمت قبل دیدید، مقادیر اولیهای برای Database و جداولمان مشخص کردیم. برای جدول Customer این دادهها را داشتیم:
Family | Name | ID |
Nasiri | Vahid | یک مقدار Guid |
Akbari | Mohsen | یک مقدار Guid |
Jamshidi | Mohsen | یک مقدار Guid |
ID توسط Database تولید میشوند به همین دلیل از ذکر مقداری مشخص خودداری شده است.
به کد زیر دقت کنید:
private static void Query7() { using (var context = new StoreDbContext()) { // Add context.Customers.Add(new Customer { Name = "Ali", Family = "Jamshidi" }); // change var customer1 = context.Customers.Single(c => c.Family == "Jamshidi"); customer1.Name = "Mohammad"; // Remove var customer2 = context.Customers.Single(c => c.Family == "Akbari"); context.Customers.Remove(customer2); var customers = context.Customers.Where(c => c.Name != "Vahid"); foreach (var cust in customers) { Console.WriteLine("Customer Name: {0}, Customer Family: {1}", cust.Name, cust.Family) } } }
همانطور که مشاهده میکنید عمل اضافه، تغییر و حذف روی Customer انجام شده ولی هنوز هیچ تغییری در Database ذخیره نشده است. آخرین پرس و جو چه نتیجه ای را دربر خواهد داشت؟
Customer Name: Mohammad, Customer Family: Jamshidi
Customer Name: Mohsen, Customer Family: Akbari
بله، فقط تغییر یک موجودیت در نظر گرفته شده است ولی اضافه و حذف نه!
نتیجه مهمی که حاصل میشود این است که در پرس و جوهایی که روی Database اجرا میشوند سه مورد را باید در نظر داشت:
- داده هایی که اخیرا به DbContext اضافه شدهاند ولی هنوز در Database ذخیره نشدهاند، درنظر گرفته نخواهند شد.
- داده هایی که در DbContext حذف شدهاند ولی در Database هستند، در نتیجه پرس و جو خواهند بود.
- داده هایی که قبلا از database توسط پرس و جوی دیگری گرفته شده و تغییر کردهاند، آن تغییرات در نتیجه پرس و جو موثر خواهند بود.
پس پرس و جوهای LINQ ابتدا روی database انجام میشوند و idهای بازگشت داده شده با idهای موجود در DbContext مطابقت داده میشوند یا در DbContext وجود دارند که در این صورت آن موجودیت بازگشت داده میشود یا وجود ندارند که در این صورت موجودیتی که از Database خوانده شده، بازگشت داده میشوند.
برای درک بیشتر کد زیر را در نظر بگیرید:
private static void Query7_1() { using (var context = new StoreDbContext()) { // Add context.Customers.Add(new Customer { Name = "Ali", Family = "Jamshidi" }); // change var customer1 = context.Customers.Single(c => c.Family == "Jamshidi"); customer1.Name = "Vahid"; // Remove var customer2 = context.Customers.Single(c => c.Family == "Akbari"); context.Customers.Remove(customer2); var customers = context.Customers.Where(c => c.Name != "Vahid"); foreach (var cust in customers) { Console.WriteLine("Customer Name: {0}, Customer Family: {1}", cust.Name, cust.Family) } } }
Customer Name: Vahid, Customer Family: Jamshidi
Customer Name: Mohsen, Customer Family: Akbari
Vahid در خروجی آمده در صورتیکه در شرط صدق نمیکند چراکه پرس و جو روی Database زده شده، جاییکه نام این مشتری Mohsen بوده اما موجودیتی بازگشت داده شده که دارای همان Id هست اما در DbContext دستخوش تغییر شده است.
Local:همانطور که قبلا اشاره شد خصوصیتی از DbSet میباشد که شامل تمام داده هایی هست که:
- اخیرا از database پرس و جو شده است (میتواند تغییر کرده یا نکرده باشد)
- اخیرا به Context اضافه شده است (توسط متد Add)
دقت شود که Local شامل دادههایی که از database خوانده شده و از Context، حذف (Remove) شدهاند، نمیباشد.
نوع این خصوصیت ObservableCollection میباشد که میتوان از آن برای Binding در پروژههای ویندوزی استفاده کرد.
به کد زیر دقت کنید:
private static void Query8() { using (var context = new StoreDbContext()) { // Add context.Customers.Add(new Customer { Name = "Ali", Family = "Jamshidi" }); // change var customer1 = context.Customers.Single(c => c.Family == "Jamshidi"); customer1.Name = "Mohammad"; // Remove var customer2 = context.Customers.Single(c => c.Family == "Akbari"); context.Customers.Remove(customer2); var customers = context.Customers.Local; foreach (var cust in customers) { Console.WriteLine("Customer Name: {0}, Customer Family: {1}", cust.Name, cust.Family); } } }
Customer Name: Ali, Customer Family: Jamshidi
Customer Name: Mohammad, Customer Family: Jamshidi
همانطور که ملاحظه میکنید Local شامل Ali Jamshidi که اخیرا اضافه شده (ولی در Database ذخیره نشده) و Mohammad Jamshidi که از Database خوانده شده و تغییر کرده، میباشد اما شامل Mohsen Akbari که از Database خوانده شده اما در Context حذف شده است، نمیباشد.
میتوان روی Local نیز پرس و جوی اجرا کرد. در این صورت از پروایدر LINQ To Object استفاده خواهد شد و درنتیجه دست بازتر هست و تمام امکانات این پروایدر میتوان استفاده کرد.
Load: یکی دیگر از مواردی که باعث اجرای پرس و جو میشود متد Load میباشد که یک Extension Method میباشد. این متد در حقیقت یک پیمایش روی پرس و جو انجام میدهد و باعث بارگذاری دادهها در Context میشود. مانند استفاده از ToList البته بدون ساختن List که سربار ایجاد میکند.
private static void Query9() { using (var context = new StoreDbContext()) { var customers = context.Customers.Where(c => c.Name == "Mohsen"); customers.Load(); foreach (var cust in context.Customers.Local) { Console.WriteLine("Customer Name: {0}, Customer Family: {1}", cust.Name, cust.Family); } } // Output: // Customer Name: Mohsen, Customer Family: Akbari // Customer Name: Mohsen, Customer Family: Jamshidi }