فرض کنید ساختار زیر را در مدل ساخته شده به وسیلهی Entity framework در پروژهی خود داریم .
جدول Post با جدول GroupsDetail ارتباط یک به چند و در مقابل ان جدول GroupsDetail با جدول PostGroup ارتباط چند به یک دارد . به زبان ساده ما تعدادی گروه بندی برای مطالب داریم (در جدول PostGroup) و میتوانیم برای هر مطلب تعدادی از گروهها را در جدول GroupsDetail مشخص کنیم ...
فکر میکنم همین مقدار توضیح به اندازهی کافی برای درک روابط مشخص شده در مدل رابطه ای مفروض کفایت کند.
حالا فرض کنید ما میخواهیم لیستی از عنوان مطالب موجود به همراه [نام] گروههای هر مطلب را داشته باشیم .
توجه شما رو به قطعه کد سادهی زیر جلب میکنم:
همانطور که شاهد هستید در قطعه کد بالا توسط خواص راهبری (Navigation Properties ) به صورت مستقیم نام گروههای ثبت شده برای هر مطلب در جدول GroupsDetail را از جدول PostGroup استخراج کردیم . خب تا اینجا مسئله ای وجود نداشت ( البته با ORMها این کار بسیار سهل و اسان شده است تا جایی که در حالت عادی برای همین کار باید کلی join نویسی کرد و .... در کل خدارو شکر که از دست کارهای تکراری و خسته کننده توسط این موجودات مهربان (ORM's) نجات یافتیم )...
خب میرسیم به ادامهی مطلبمون . نتیجهی این query چه خواهد بود ؟ کاملا واضح است که ما تعداد دلخواهی از فیلدها رو برای واکشی مشخص کردیم پس در نتیجه نوع داده ای که توسط این query بازگشت داده خواهد شد یک لیست از یک نوع بی نام میباشد ... چگونه از نتیجهی بازگشتی این query در صورت ارسال اون به عنوان یک پارامتر به یک تابع استفاده کنیم ؟ اگر ما تمامی فیلدهای جدول Post را واکشی میکریم مقدار بازگشتی یک لیست از نوع Post بود که به راحتی قابل استفاده بود مثل مثال زیر
اما حالا با یک لیست از یک نوع بی نام رو به رو هستیم ... چند راه مختلف برای دسترسی به این گونه از مقادیر بازگشتی داریم .
1 : استفاده از Reflection برای دسترسی به فیلدهای مشخص شده .
2 : تعریف یک مدل کامل بر اساس فیلدهای مشخص شدهی بازگشتی و ارسال یک لیست از نوع تعریف شده به تابع . ( به نظرم این روش خسته کنندست و زیاد شکیل نیست چون برای هر query خاص مجبوریم یک مدل کلی تعریف کنیم و این باعث میشه تعداد زیادی مدل در نهایت داشته باشیم که استفادهی زیادی از اونها نمیشه عملا )
3 : استفاده از یکی از روشهای خلاقانهی تبدیل نوع Anonymousها .
روش سوم روش مورد علاقهی من هست و انعطاف بالایی داره و خیلی هم شیکو مجلسیه ! در ضمن این روش که قراره ذکر بشه کاربردهای فراوانی داره که این مورد فقط یکی از اونهاست
خب بریم سر اصل مطلب . به کد زیر توجه کنید :
در کد بالا به صورت تو در تو از انواع بی نام استفاده شده تا مطلب براتون خوب جا بیوفته . یعنی یک نوع بی نام که یکی از فیلدهای اون یک لیست از یک نوع بی نام دیگست ... خب میبینید که خیلی راحت با دو تابع ما تبدیل انواع بی نام رو به صورت inline انجام دادیم و ازش استفاده کردیم . بدون اینکه نیاز باشه ما یک مدل مجزا ایجاد کنیم ...
تابع CreateGenericListFromAnonymous : یک object رو میگیره و اون رو به یک لیست تبدیل میکنه بر اساس نوعی که به صورت inline براش مشخص میکنیم .
تابع CreateEmptyAnonymousIEnumerable یک لیست از نوع IEnumerable رو بر اساس نوعی که به صورت inline براش مشخص کردیم بر میگردونه . دلیل اینکه من در اینجا این تابع رو نوشتم این بود که ما در query یک فیلد با نام GNames داشتیم که مجموعه ای از نام گروههای هر مطلب بود که از نوع IEnumerable هستش . در واقع ما در اینجا نوع بی نامی داریم که یکی از فیلدهای اون یک لیست از یک نوع بی نام دیگست . امیدوارم مطلب براتون جا افتاده باشه.
دوستان عزیز سوالی بود در قسمت نظرات مطرح کنید.
جدول Post با جدول GroupsDetail ارتباط یک به چند و در مقابل ان جدول GroupsDetail با جدول PostGroup ارتباط چند به یک دارد . به زبان ساده ما تعدادی گروه بندی برای مطالب داریم (در جدول PostGroup) و میتوانیم برای هر مطلب تعدادی از گروهها را در جدول GroupsDetail مشخص کنیم ...
فکر میکنم همین مقدار توضیح به اندازهی کافی برای درک روابط مشخص شده در مدل رابطه ای مفروض کفایت کند.
حالا فرض کنید ما میخواهیم لیستی از عنوان مطالب موجود به همراه [نام] گروههای هر مطلب را داشته باشیم .
توجه شما رو به قطعه کد سادهی زیر جلب میکنم:
var context = new Models.EntitiesConnection(); var query = context.Posts.Select(pst => new { id = pst.id, Title = pst.Title, GNames = pst.GroupsDetails.Select(grd => new { Name = grd.PostGroup.name }) }) .OrderByDescending(c => c.id) .ToList();
خب میرسیم به ادامهی مطلبمون . نتیجهی این query چه خواهد بود ؟ کاملا واضح است که ما تعداد دلخواهی از فیلدها رو برای واکشی مشخص کردیم پس در نتیجه نوع داده ای که توسط این query بازگشت داده خواهد شد یک لیست از یک نوع بی نام میباشد ... چگونه از نتیجهی بازگشتی این query در صورت ارسال اون به عنوان یک پارامتر به یک تابع استفاده کنیم ؟ اگر ما تمامی فیلدهای جدول Post را واکشی میکریم مقدار بازگشتی یک لیست از نوع Post بود که به راحتی قابل استفاده بود مثل مثال زیر
public bool myfunc(List<Post> query) { foreach (var item in query) { ..... string title = item.Title; } ...return true; } . . . var context = new Models.EntitiesConnection(); var queryx = context.Posts.ToList(); .... myfunc(queryx );
1 : استفاده از Reflection برای دسترسی به فیلدهای مشخص شده .
2 : تعریف یک مدل کامل بر اساس فیلدهای مشخص شدهی بازگشتی و ارسال یک لیست از نوع تعریف شده به تابع . ( به نظرم این روش خسته کنندست و زیاد شکیل نیست چون برای هر query خاص مجبوریم یک مدل کلی تعریف کنیم و این باعث میشه تعداد زیادی مدل در نهایت داشته باشیم که استفادهی زیادی از اونها نمیشه عملا )
3 : استفاده از یکی از روشهای خلاقانهی تبدیل نوع Anonymousها .
روش سوم روش مورد علاقهی من هست و انعطاف بالایی داره و خیلی هم شیکو مجلسیه ! در ضمن این روش که قراره ذکر بشه کاربردهای فراوانی داره که این مورد فقط یکی از اونهاست
خب بریم سر اصل مطلب . به کد زیر توجه کنید :
public static List<T> CreateGenericListFromAnonymous<T>(object obj, T example) { return (List<T>)obj; } public static IEnumerable<T> CreateEmptyAnonymousIEnumerable<T>(T example) { return new List<T>(); ; } //// public bool myfunc(object query) { var cquery = CreateGenericListFromAnonymous(query, new { id = 0, Title = string.Empty, GNames = CreateEmptyAnonymousIEnumerable(new { Name = string.Empty }) }); foreach (var item in cquery) { string title = item.Title; foreach (var gname in item.GNames) { string gn = gname.Name; } . . . } return false; } . . . var context = new Models.EntitiesConnection(); var query = context.Posts.Select(pst => new { id = pst.id, Title = pst.Title, GNames = pst.GroupsDetails.Select(grd => new { Name = grd.PostGroup.name }) }).OrderByDescending(c => c.id); myfunc(query.ToList());
تابع CreateGenericListFromAnonymous : یک object رو میگیره و اون رو به یک لیست تبدیل میکنه بر اساس نوعی که به صورت inline براش مشخص میکنیم .
تابع CreateEmptyAnonymousIEnumerable یک لیست از نوع IEnumerable رو بر اساس نوعی که به صورت inline براش مشخص کردیم بر میگردونه . دلیل اینکه من در اینجا این تابع رو نوشتم این بود که ما در query یک فیلد با نام GNames داشتیم که مجموعه ای از نام گروههای هر مطلب بود که از نوع IEnumerable هستش . در واقع ما در اینجا نوع بی نامی داریم که یکی از فیلدهای اون یک لیست از یک نوع بی نام دیگست . امیدوارم مطلب براتون جا افتاده باشه.
دوستان عزیز سوالی بود در قسمت نظرات مطرح کنید.