دوره مجازی #C (جلسه 26): تکمیل و جمع بندی مطالب مرتبط با Linq و Entity Framework



visibility  
mode_comment   ۲۴

در این جلسه به تکمیل و جمع بندی مطالب مرتبط با Linq و Entity Framework خواهیم پرداخت. در قسمت اول این قسمت به بررسی دقیق تر Linq می پردازیم و انواع عملیات مختلف را توسط این تکنولوژی بررسی و فراخواهیم گرفت. در قسمت دوم هم به طور کلی با معماری Model First در Entity Framework آشنا می شویم.

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

  • آشنایی با عملیات گروه بندی در Linq و کوئری مرتبط
  • نحوه ی استفاده از Aggregate Function ها در Linq
  • آشنایی با نحوه ی مدیریت رشته های در صفحه ی کنسول
  • معرفی علمیات Join در Linq
  • معرفی کامل توابع کاربردی Extension Method ها در Linq و استفاده از آن ها در مدیریت لیست ها و آرایه ها
  • نحوه ی استفاده از View ها و Procedure ها و توابع نوشته شده در SQL Server
  • آشنایی با نحوه ی استفاده از Entity Framework با معماری Model First
  • معرفی مفهوم Entity
  • نحوه ی ایجاد Relation ها در معماری Model First

با پایان این جلسه، فصل چهارم نیز به پایان می رسد و از جلسه ی آینده وارد مباحث مربوط به طراحی لایه ی Presentation می شویم و عملا به طراحی فرم ها و نرم افزارهای کاربردی ویندوزی خواهیم پرداخت.

info توجه

این مطلب یک جلسه از دوره آموزش #C می باشد و برای مشاهده آن باید در دوره ثبت نام کنید.

ثبت نام در دوره آموزش #C

comment دیدگاه کاربران
محمد مهدی اکرمی replyپاسخ

سلام استاد
دوره کی تموم میشه تا پکیج ها ارسال بشن ؟
با تشکر

محمد مهدی اکرمی

الان جواب ندادید یعنی نباید این جا سوال میکردم ؟

پژمان replyپاسخ

. از آنجا که در روش سنتی ADO.net متوجه شدیم لایه Bll رو در namespace مجزا و در قالب یک فایل dll و جهت صحت اطلاعات ورودی در لایه PRE، مورد استفاده قرار دادیم که لایه PRE هم خودش در کلاس Program و متد main پیاده سازی کردیم. در استفاده از روش EntityFrameWork در حالت چند لایه(یعنی در معماری EF لایه های DAL ، BLL و BO و PRE به ترتیب همان ADO Data Provider ، Entity Data Provider و Object Services هستند؟) چون اشاره ای ولو کوتاه که در مقام مقایسه با مثال جلسه 24 و معماری چند لایه باشه انجام نشد. مثلا آیا نیازی نیست که یک لایه مشابه Bll برای صحت ورود اطلاعات در کوئریهایی مثل کوئری زیر در نظر بگیریم.
ClassRoom c4 = new ClassRoom();
c4.Title = “AutoCad-104”;
c4.Floor = 3;

context.Buildings.Where(building => building.Id == 1).FirstOrDefault().ClassRooms.Add(c4);

چون اگر Id مورد نظر یافت نشود default بازگشت میدهد که احتمالا null باشه که null هم آیتم title نداره پس دچار exception handling میشیم. آیا در مدل EF داستان فرق میکنه به نسبت رویکرد سنتی ADO.net !؟ چون در مثال مربوط به لایه بندی در رویکرد سنتی موارد فوق رو رعایت میکردیم(MultiLayerTest).

آرین زارعی

با در نظر گرفتن entity framework معماری ها متفاوت میشود. رویکرد ها زیاد است. در جلسات آتی و تا انتهای دوره به ویژه در پروژه پایانی توضیحاتی راجع به مشکلات و رویکرد های مختلف داده شده.

پژمان replyپاسخ

لزوم استفاده از کلید خارجی Product_Factory_Id در مثال زیر چیه؟ خود a.Product_Factory
کار ما رو راه میاندازه که!!
var q = from a in context.BuyFactorDetails
group a by (new { a.Product_Factory_Id, a.Product_Factory }) into g
select (new { g.Key.Product_Factory.Product.Title, FactoryTitle = g.Key.Product_Factory.Factory.Title, sum = g.Sum(b => b.Quantity * b.UnitPrice

آرین زارعی

نه مشکل ایجاد میکنه. به صورت مثال در ویدیو توجه کنید.

پژمان replyپاسخ

شما در مثال زیر:
var q = (from a in context.SellFactorDetails
select a);
var q2 = (from a in q
group a by (new { a.SellFactor.DateOfSell.Value.Month }) into g
select (new { g.Key.Month, sum = g.Sum(b => b.Quantity * b.UnitPrice) }));

foreach (var item in q2)
{
Console.WriteLine(item.Month + “=>” + item.sum);

بدلیل اینکه فیلد value و سپس Month در دیتا بیس وجود خارجی ندارد ابتدا آن را درون یک جنریک لیست دیگر ذخیره کردید وسپس عملیات گروپینگ انجام دادی و لی در مثال مدل extention method آن این نکته رو رعایت نکردید:

var q = context.SellFactorDetails.GroupBy(a => a.SellFactor.DateOfSell.Value.Month);
foreach (var item in q.ToList())
{
Console.WriteLine(item.Key + “–>” + item.Sum(a => a.Quantity * a.UnitPrice));
}و مستقیما گروپینگ رو روی SellFactorDetails اجرا کردید. و همینطور مثال بعد از آن که جمع مقادیر بعد از تاریخ بخصوصی رو به دست آوردید و از کلمه کلیدی value استفاده فرمودی. آیا این کار اشتباهی بوجود نمیاره!!؟

آرین زارعی

نه مشکلی ندارد. در ویدیو علت کار اول توضیح داده شده .

پژمان replyپاسخ

علت اینکه نویجیشن پراپرتی Product_Factory درون جداول Product و Factory جمع بسته نشده به علت Junction table بودن آن است؟ کما اینکه هنگام فراخوانی در کوئری نیز بصورت context.Product_Factory نمایش داده میشود، چون کلا از نظر context تمام تیبلها لیست تلقی میشوند. در صورتیکه در حالت چند به چند مانند مثال Courses و Semesters در شرایطی که در دیتابیس، بصورت Junction table معرفی شده اند، مانند مثال HyperMarket نیستند و هنگام استفاده از context جمع بسته میشوند. Context.Semesters . البته برای سایر ارتباطات یک به چند دیتابیسهای دیگر هم کلا اسامی تیبلها همراه با context بصورت جمع ظاهر میشوند ولی گویا junction table در حالت یک به چند (و نه چند به چند مانند مثال CourseSystem) که در دیتابیس ستون اضافه داشته باشد در هنگام فراخوانی با context ، s جمع نمیگیرد. درسته؟

آرین زارعی

جواب این سوالاتتون در ویدیو ها به طور کامل و واضح موجود است. در همین جلسه و جلسات بعد.

پژمان replyپاسخ

در مثال متد Reverse() مانند زیر قابل پیاده سازی نیست زیرا با اروری با این موضوع روبرو میشویم:
” foreach نمیتواند بر روی متغیرهای void کار کند زیرا حاوی GetEnumerator نیستند”. با این اوصاف دستور context.Products.ToList() هم مقداری بازگشت نمیدهد ولی میتوان بجای آیتم Collection در حلقه foreach از آن استفاده نمود. یعنی هر دو حالت زیر را امتحان کردم ولی پاسخ نداد. چرا؟

foreach (Product item in q.Reverse())
{
Console.WriteLine(item.Title);
}

List q2 = q.Reverse();
foreach (Product item in q2)
{
Console.WriteLine(item.Title);
}

منظور اینست که درسته که متد Reverse() مقداری بازگشت نمیدهد ولی آیا مگر نه اینکه میشود مقدار یه متغیر حالا از هر نوعی را درون متغیری از همان نوع واریز کرد. مثل int m1 = m2 . ولی با روش دوم فوق الذکر متاسفانه باز ارور میدهد. علت چیست؟

آرین زارعی

دوست عزیز tolist مقدار بازگشتی دارد. لطفا دقیقتر بررسی کنید. reverse هم ienumerable بر میگرداند و مشکلی ندارد. ارورتون شاید به خاطر چیز دیگریست.
به این لینک توجه کنید : لینک
در ضمن برای رفع این مشکلاتون میتونید از سایت مایکروسافت استفاده کنید. اونجا خیلی از این سوالاتون رو میتونید جواب بگیرید.

پژمان replyپاسخ

شما در مثال DateTime مربوط به جلسه چهاردهم از فصل دوم مثالی از TimeSpan زده بودید که بنده به این شکل تغییرش داده ام:
DateTime dt2 = new DateTime(2017, 05, 13);

Console.WriteLine(dt2.Subtract(DateTime.Now).Days);
خروجی در تاریخ 18/05/2017 که من کد رو میزدم برابر با عدد 5 هست. یعنی پنج روز تا رسیدن به زمان مورد نظر. ولی شما در مثال مربوط به Contains و برای توضیح این متد که در برخی موارد نمیتوان همچون این متد مستقیم بر روی دیتا بیس کوئری زد مثال زیر رو بکار بردید:

foreach (var item in context.BuyFactorDetails.Where(a => a.BuyFactor.DateOfBuy.Value.Date.Subtract(DateTime.Now).Days > 5))
{
Console.WriteLine(item.Product_Factory.Product.Title);
}
که همونطور که قبلا هم توضیح فرموده بودی پراپرتی Value درSql ناشناختس و ارور ران تایم خواهد داد. اما سئوال اصلی اینجاست در بحث متغیر حاصله تایم اسپن، از مقدار تاریخ خرید کالا تا به امروز شما علامت بزرگتر از پنج قرار داده اید و در توضیحات فرمودی یعنی کالاهایییکه طی پنج روز قبل تا به امروز خریداری شده و این توضیح کاملا با آموزشهای سابق شما مغایرت داره چرا که اگر عدد خروجی حاصل از عبارت فوق مثبت شود یعنی هنوز به تایم مورد نظر نرسیده ایم. مثل همون مثال تاریخ تولد که بنده قسمتی از کدش رو بالا نوشته ام و خروجیش نسبت به تاریخ فعلی بنده مثبت خواهد شد. ولی شما میفرمایی طی 5 روز گذشته!!! جسارتا به نظر من توضیح شما برای عبارت فوق اشتباست. در غیر اینصورت بنده رو توجیه فرمایید.

آرین زارعی

فکر کنم عوض کردن جای datetime.now با dateofbuy مشکل رو حل کنه

پژمان replyپاسخ

بحث دسیمال Nullable و استفاده ازپراپرتی value که در انتهای کد استفاده شده، برای متد Sum در مثال زیر متوجه نمیشم.
decimal num = Convert.ToDecimal( q.Where(a => a.SellFactor.DateOfSell.Value > new DateTime(2012, 01, 01)).Sum(b => b.UnitPrice * b.Quantity).Value);

ولی در مثالهای مربوط به Sum که قبل از این مطرح فرمودی از Value برای خروجی متد Sum استفاده نکرده اید. تفاوت در کجاست؟

آرین زارعی

به این لینک مراجعه کنید
لینک

پژمان replyپاسخ

فرق متد ریاضیات ی که در دستورات Linq استفاده میشود مثل Min و Max با متد Min و Max استاتیک کلاس Math ، در شکل استفاده در کجاست؟ مثل زمانیکه بر روی یک آرایه یک بعدی محدود از نوع int اعمال میشوند.

آرین زارعی

خب خودتون دارید میگید در مورد ریاضیاتی باید از کلاس math استفاده کنید ولی در حالت دوم میتونید روی لیستتون نقطه بزارید و به عنوان یک متد ارث بری شده از کلاس های انتزاعی ازش استفاده کنید.

پژمان replyپاسخ

چگونه میتوان پروسیجر و فانکشن و ویو جدیدی که در دیتا بیس اضافه شده اند به مدل مپ شده از قبل، اضافه کرد تا بتوان درون کد مورد نظر و با نوشتن آبجکت context قابل دسترسی باشند. چرا که هنگامیکه گزینه update model رو از منوی حاصل از راست کلیک بر روی صفحه سفید رنگ مدل مپ شده انتخاب میکنیم در قسمت stored procedure ، پروسیجر جدید که در دیتایس ایجاد کرده ام، درپنجره مورد نظر نمایش داده میشود و هنگام انتخاب و زدن دکمه اوکی لودینگ بار پر میشود و احتمالا اکنون دیگر باید به مدل ما اضافه شده باشد. ولی… به هیچ وجه قابل دسترسی نیستند. یا مثلا در تب رفرش ظاهر میشود ولی دکمه FINISH رو که میزنم تیبل ویوها رو که در ابتدای مپ کردن همراه با تیبلهای دیتابیس و در صفحه سفید رنگ مدل ما اضافه شده بودند رو نمایش میده ولی، اثری از پروسیجرها و فانکشن ها نیست و هنگام تایپ کد و با زدن کد context. و به محض نوشتن دات بعد از context هیچ عنوانی از پروسیجرها و فانکشنهای اضافه شده به دیتابیس، ظاهر نمیشود.

آرین زارعی

یک مشکلی که ORM ها میتونند داشته باشند همین بحث است. البته این یک باگ کوچیک از ویژوال استودیو هم هست که معمولا با rebuild کردن سلوشن یا باز و بسته کردن آن حل میشود. نه فقط در entityframework بلکه در مواردی دیگر هم شاید به این مشکل بر بخورید.

پژمان replyپاسخ

پیرامون خروجی TABLE – Value فانکشنها صحبتی نفرمودی! مهم نیست این مبحث؟ چون حتی یک مثال ولو ساده هم حل نکردید پیرامون این قضیه البته شفاها بارها اشاره کردید در این مورد و در طول دوره. مثلا شبه ای که ابتدا به ساکن وجود داره نحوه بیان نوع خروجی فانکشن مورد نظر توسط کد سی شارپ و در Linq میباشد. یعنی جلوی آیتم RETURN ی که در مقابل نام فانکشن نوشته میشه چه باید بنویسیم؟
چه در رویکرد سنتی ADO.net و چه در مورد نحوه کد زنی در EntityFrameWork.. هیچگونه مثالی حل نشده.

آرین زارعی

این مبحث اهمیت خودش رو داره و کاربردهای خودش رو. با یک جستجوی ساده در اینترنت میتونید به چندین مثال دست پیدا کنید. به عنوان یک فردی که دارید برنامه نویسی رو در سطحی تقریبا پیشرفته دنبال میکنید، این یک مهارت ضروری است.

پژمان replyپاسخ

1- تفاوت Console.buffersize و Console.bufferheight
2- نحوه استفاده از Resharper. پیرو راهنمایی شما ریشارپر رو دانلود و نصب کردم ولی خیلی گیره. آزادی عمل قبلی رو ندارم مدام سر تمیز کاری کدها آلرم میده و آیکونهای مختلف نشون میده. سعی کردم ازش استفاده بهینه کنم ولی نمیدونم چرا کدهامو بهم میریزه!!

در انتها و مجددا، پیشاپیش ممنون بابت صبر و شکیبایی شما در پاسخ به سئوالات بالا

آرین زارعی

سایز در اصل اندازه ی بافر صفحه کنسول است ولی ارتفاع اندازه ی نمایشی
در باره ی ریشارپر باید خودتون باهاش یادبگیرید چطور کار کنید.

ارسال نظرات

کاربر گرامی، امکان ارسال نظر و پشتیبانی برای دوره های مجازی فقط برای دانشجویان این دوره امکان پذیر می باشد.