اشتراکها
خیلی ممنون بابت این نکته.
ولی دیگه سعی کنید که کوچ کنید به MVC. تو وب فرم آدم نمیدونه تو وب هست یا ویندوز فرم. یک وب مصنوعی.
بازخوردهای دوره
استفاده از Async و Await در برنامههای ASP.NET MVC
با تشکر؛ حدودا یک ماهه فکرم درگیر دقیقا همین موضوع بود و دقیقا 24 ساعته دارم توی وب سرچ میکنم. آخرم به نتیجه مطلوب نرسیدم تا این کامنت شما رو دیدم دقیقا سوال من همین بود و تشکر ویژه دارم .
اما چرا بعد حدود 9 سال کار با asp.net تازه یاد این ویژگی افتادم و برام چالش شد، صرفا دلیلش این بود که در همین سایت خودتون مباحث مربوط به طراحی برنامههای با میزان کاربر بالا مطالعه میکردم که دوستان توضیح داده بودن و فکر منو سمتی برد که تصور کنم مسیر رو اشتباه میرم که به مباحث برنامه نویسی موازی و چند نخی رسیدم و بعد کلی تحقیق بررسی فهمیدم برنامه نویسی موازی واقعا خطرات پیشبینی نشدهای برای سیستم خصوصا در رابطه با استفاده از io بهوجود میارد و کماکان گیجتر هم شدم که اگر خوب نیست یا طراحی آن خیلی حساس هست و چند نخی هم زیاد باعث افزایش سرعت نمیشود، پس سیستمهای بیگ اسکیل مثل اینستا و فیسبوک و ... که کاربران میلیونی دارند چطور طراحی و چطور کار میشوند با اینکه asp.net core در سطح 7 فریم ورک سریع دنیا مطرح هست ؟!
نظرات مطالب
آموزش Prism #3
بسیار ساده است. شما نیاز به طراحی یک UnitOfWork بر اساس EF دارید(^). بعد از آن کافیست کدهای مورد نظر برای عملیات CRUD رو در ViewModelهای هر ماژول بنویسید. در پروژههای Silverlight هم میتونید از RIA Service و EF استفاده کنید. سعی میکنم در صورت داشتن زمان کافی یک پست را به این مطلب اختصاص بدم.
نظرات اشتراکها
نسخه فیسبوک مای اس کیو ال
البته این سایتهای بزرگ بیشتر از بانکهای NoSQL استفاده میکنند: http://stackoverflow.com/a/1113476
نظرات اشتراکها
Kendo UI Q2 2012 BETA available now
هاستینگ تلریک و خیلی از سایتهای دیگر بازه IP ایران رو بستن.
نظرات مطالب
CAPTCHAfa
چه جالب!
امیدوارم استفاده از کپتچای فارسی در سایتهای فارسی مرسوم بشه
امیدوارم استفاده از کپتچای فارسی در سایتهای فارسی مرسوم بشه
مطالب
EF Code First #11
استفاده از الگوی Repository اضافی در EF Code first؛ آری یا خیر؟!
اگر در ویژوال استودیو، اشارهگر ماوس را بر روی تعریف DbContext قرار دهیم، راهنمای زیر ظاهر میشود:
A DbContext instance represents a combination of the Unit Of Work and Repository patterns such that
it can be used to query from a database and group together changes that will then be written back to
the store as a unit. DbContext is conceptually similar to ObjectContext.
در اینجا تیم EF صراحتا عنوان میکند که DbContext در EF Code first همان الگوی Unit Of Work را پیاده سازی کرده و در داخل کلاس مشتق شده از آن، DbSetها همان Repositories هستند (فقط نامها تغییر کردهاند؛ اصول یکی است).
به عبارت دیگر با نام بردن صریح از این الگوها، مقصود زیر را دنبال میکنند:
لطفا بر روی این لایه Abstraction ایی که ما تهیه دیدهایم، یک لایه Abstraction دیگر را ایجاد نکنید!
«لایه Abstraction دیگر» یعنی پیاده سازی الگوهای Unit Of Work و Repository جدید، برفراز الگوهای Unit Of Work و Repository توکار موجود!
کار اضافهای که در بسیاری از سایتها مشاهده میشود و ... متاسفانه اکثر آنها هم اشتباه هستند! در ذیل روشهای تشخیص پیاده سازیهای نادرست الگوی Repository را بر خواهیم شمرد:
1) قرار دادن متد Save تغییرات نهایی انجام شده، در داخل کلاس Repository
متد Save باید داخل کلاس Unit of work تعریف شود نه داخل کلاس Repository. دقیقا همان کاری که در EF Code first به درستی انجام شده. متد SaveChanges توسط DbContext ارائه میشود. علت هم این است که در زمان Save ممکن است با چندین Entity و چندین جدول مشغول به کار باشیم. حاصل یک تراکنش، باید نهایتا ذخیره شود نه اینکه هر کدام از اینها، تراکنش خاص خودشان را داشته باشند.
2) نداشتن درکی از الگوی Unit of work
به Unit of work به شکل یک تراکنش نگاه کنید. در داخل آن با انواع و اقسام موجودیتها از کلاسها و جداول مختلف کار شده و حاصل عملیات، به بانک اطلاعاتی اعمال میگردد. پیاده سازیهای اشتباه الگوی Repository، تمام امکانات را در داخل همان کلاس Repository قرار میدهند؛ که اشتباه است. این نوع کلاسها فقط برای کار با یک Entity بهینه شدهاند؛ در حالیکه در دنیای واقعی، اطلاعات ممکن است از دو Entity مختلف دریافت و نتیجه محاسبات مفروضی به Entity سوم اعمال شود. تمام این عملیات یک تراکنش را تشکیل میدهد، نه اینکه هر کدام، تراکنش مجزای خود را داشته باشند.
3) وهله سازی از DbContext به صورت مستقیم داخل کلاس Repository
4) Dispose اشیاء DbContext داخل کلاس Repository
هر بار وهله سازی DbContext مساوی است با باز شدن یک اتصال به بانک اطلاعاتی و همچنین از آنجائیکه راهنمای ذکر شده فوق را در مورد DbContext مطالعه نکردهاند، زمانیکه در یک متد با سه وهله از سه Repository موجودیتهای مختلف کار میکنید، سه تراکنش و سه اتصال مختلف به بانک اطلاعاتی گشوده شده است. این مورد ذاتا اشتباه است و سربار بالایی را نیز به همراه دارد.
ضمن اینکه بستن DbContext در یک Repository، امکان اعمال کوئریهای بعدی LINQ را غیرممکن میکند. به ظاهر یک شیء IQueryable در اختیار داریم که میتوان بر روی آن انواع و اقسام کوئریهای LINQ را تعریف کرد اما ... در اینجا با LINQ to Objects که بر روی اطلاعات موجود در حافظه کار میکند سر و کار نداریم. اتصال به بانک اطلاعاتی با بستن DbContext قطع شده، بنابراین کوئری LINQ بعدی شما کار نخواهد کرد.
همچنین در EF نمیتوان یک Entity را از یک Context به Context دیگری ارسال کرد. در پیاده سازی صحیح الگوی Repository (دقیقا همان چیزی که در EF Code first به صورت توکار وجود دارد)، Context باید بین Repositories که در اینجا فقط نامش DbSet تعریف شده، به اشتراک گذاشته شود. علت هم این است که EF از Context برای ردیابی تغییرات انجام شده بر روی موجودیتها استفاده میکند (همان سطح اول کش که در قسمتهای قبل به آن اشاره شد). اگر به ازای هر Repository یکبار وهله سازی DbContext انجام شود، هر کدام کش جداگانه خاص خود را خواهند داشت.
5) عدم امکان استفاده از تنها یک DbConetext به ازای یک Http Request
هنگامیکه وهله سازی DbContext به داخل یک Repository منتقل میشود و الگوی واحد کار رعایت نمیگردد، امکان به اشتراک گذاری آن بین Repositoryهای تعریف شده وجود نخواهد داشت. این مساله در برنامههای وب سبب کاهش کارآیی میگردد (باز و بسته شدن بیش از حد اتصال به بانک اطلاعاتی در حالیکه میشد تمام این عملیات را با یک DbContext انجام داد).
نمونهای از این پیاده سازی اشتباه را در اینجا میتوانید پیدا کنید. متاسفانه شبیه به همین پیاده سازی، در پروژه MVC Scaffolding نیز بکارگرفته شده است.
چرا تعریف لایه دیگری بر روی لایه Abstraction موجود در EF Code first اشتباه است؟
یکی از دلایلی که حین تعریف الگوی Repository دوم بر روی لایه موجود عنوان میشود، این است:
«به این ترتیب به سادگی میتوان ORM مورد استفاده را تغییر داد» چون پیاده سازی استفاده از ORM، در پشت این لایه مخفی شده و ما هر زمان که بخواهیم به ORM دیگری کوچ کنیم، فقط کافی است این لایه را تغییر دهیم و نه کل برنامه را.
ولی سؤال این است که هرچند این مساله از هزار فرسنگ بالاتر درست است، اما واقعا تابحال دیدهاید که پروژهای را با یک ORM شروع کنند و بعد سوئیچ کنند به ORM دیگری؟!
ضمنا برای اینکه واقعا لایه اضافی پیاده سازی شده انتقال پذیر باشد، شما باید کاملا دست و پای ORM موجود را بریده و تواناییهای در دسترس آن را به سطح نازلی کاهش دهید تا پیاده سازی شما قابل انتقال باشد. برای مثال یک سری از قابلیتهای پیشرفته و بسیار جالب در NH هست که در EF نیست و برعکس. آیا واقعا میتوان به همین سادگی ORM مورد استفاده را تغییر داد؟ فقط در یک حالت این امر میسر است: از قابلیتهای پیشرفته ابزار موجود استفاده نکنیم و از آن در سطحی بسیار ساده و ابتدایی کمک بگیریم تا از قابلیتهای مشترک بین ORMهای موجود استفاده شود.
ضمن اینکه مباحث نگاشت کلاسها به جداول را چکار خواهید کرد؟ EF راه و روش خاص خودش را دارد، NH چندین و چند روش خاص خودش را دارد! اینها به این سادگی قابل انتقال نیستند که شخصی عنوان کند: «هر زمان که علاقمند بودیم، ORM مورد استفاده را میشود عوض کرد!»
دلیل دومی که برای تهیه لایه اضافهتری بر روی DbContext عنوان میکنند این است:
«با استفاده از الگوی Repository نوشتن آزمونهای واحد سادهتر میشود». زمانیکه برنامه بر اساس Interfaceها کار میکند میتوان آنها را بجای اشاره به بانک اطلاعاتی، به نمونهای موجود در حافظه، در زمان آزمون تغییر داد.
این مورد در حالت کلی درست است اما .... نه در مورد بانکهای اطلاعاتی!
زمانیکه در یک آزمون واحد، پیاده سازی جدیدی از الگوی Interface مخزن ما تهیه میشود و اینبار بجای بانک اطلاعاتی با یک سری شیء قرارگرفته در حافظه سروکار داریم، آیا موارد زیر را هم میتوان به سادگی آزمایش کرد؟
ارتباطات بین جداولرا، cascade delete، فیلدهای identity، فیلدهای unique، کلیدهای ترکیبی، نوعهای خاص تعریف شده در بانک اطلاعاتی و مسایلی از این دست.
پاسخ: خیر! تغییر انجام شده، سبب کار برنامه با اطلاعات موجود در حافظه خواهد شد، یعنی LINQ to Objects.
شما در حالت استفاده از LINQ to Objects آزادی عمل فوق العادهای دارید. میتوانید از انواع و اقسام متدها حین تهیه کوئریهای LINQ استفاده کنید که هیچکدام معادلی در بانک اطلاعاتی نداشته و ... به ظاهر آزمون واحد شما پاس میشود؛ اما در عمل بر روی یک بانک اطلاعاتی واقعی کار نخواهد کرد.
البته شاید شخصی عنوان که بله میشود تمام اینها نیازمندیها را در حالت کار با اشیاء درون حافظه هم پیاده سازی کرد ولی ... در نهایت پیاده سازی آن بسیار پیچیده و در حد پیاده سازی یک بانک اطلاعاتی واقعی خواهد شد که واقعا ضرورتی ندارد.
و پاسخ صحیح در اینجا و این مساله خاص این است:
لطفا در حین کار با بانکهای اطلاعاتی مباحث mocking را فراموش کنید. بجای SQL Server، رشته اتصالی و تنظیمات برنامه را به SQL Server CE تغییر داده و آزمایشات خود را انجام دهید. پس از پایان کار هم بانک اطلاعاتی را delete کنید. به این نوع آزمونها اصطلاحا integration tests گفته میشود. لازم است برنامه با یک بانک اطلاعاتی واقعی تست شود و نه یک سری شیء ساده قرار گرفته در حافظه که هیچ قیدی همانند شرایط کار با یک بانک اطلاعاتی واقعی، بر روی آنها اعمال نمیشود.
ضمنا باید درنظر داشت بانکهای اطلاعاتی که تنها در حافظه کار کنند نیز وجود دارند. برای مثال SQLite حالت کار کردن صرفا در حافظه را پشتیبانی میکند. زمانیکه آزمون واحد شروع میشود، یک بانک اطلاعاتی واقعی را در حافظه تشکیل داده و پس از پایان کار هم ... اثری از این بانک اطلاعاتی باقی نخواهد ماند و برای این نوع کارها بسیار سریع است.
نتیجه گیری:
حین استفاده از EF code first، الگوی واحد کار، همان DbContext است و الگوی مخزن، همان DbSetها. ضرورتی به ایجاد یک لایه محافظ اضافی بر روی اینها وجود ندارد.
در اینجا بهتر است یک لایه اضافی را به نام مثلا Service ایجاد کرد و تمام اعمال کار با EF را به آن منتقل نمود. سپس در قسمتهای مختلف برنامه میتوان از متدهای این لایه استفاده کرد. به عبارتی در فایلهای Code behind برنامه شما نباید کدهای EF مشاهده شوند. یا در کنترلرهای MVC نیز به همین ترتیب. اینها مصرف کننده نهایی لایه سرویس ایجاد شده خواهند بود.
همچنین بجای نوشتن آزمونهای واحد، به Integration tests سوئیچ کنید تا بتوان برنامه را در شرایط کار با یک بانک اطلاعاتی واقعی تست کرد.
برای مطالعه بیشتر:
مطالب
خواندنیهای 2 مرداد
اس کیوال سرور
الگوهای طراحی برنامه نویسی شیءگرا
امنیت
توسعه وب
دات نت فریم ورک
دبلیو اف
سی و مشتقات
کتابهای رایگان
لینوکس
متفرقه
محیطهای مجتمع توسعه
مسایل انسانی، اجتماعی و مدیریتی برنامه نویسی
ویندوز