"c:\Program Files\Microsoft Visual Studio version\Common7\IDE\devenv.exe" /safemode /nosplash /log
// Named function function add(x, y) { return x + y; } // Anonymous function let myAdd = function(x, y) { return x+y; };
let z = 100; function addToZ(x, y) { return x + y + z; }
function add(x: number, y: number): number { return x + y; } let myAdd = function(x: number, y: number): number { return x+y; };
function PublicationMessage(year: number): string { return 'Date published: ' + year; }
let publishFunc: (someYear: number) => string;
publishFunc = PublicationMessage; let message: string = publishFunc(2016);
همچنین میتوان function type را به صورت inline نیز تعریف کرد:
let myAdd: (baseValue:number, increment:number) => number = function(x, y) { return x + y; };
Optional and Default Parameters
در جاوا اسکریپت تمامی پارامترهای یک تابع اختیاری هستند. اما TypeScript کمی متفاوت است. یعنی در حالت پیشفرض، ذکر تمامی پارامترها ضروری است؛ مگر اینکه پارامترهای موردنیاز را به صورت اختیاری تعیین کنید. به طور مثال در تابع زیر دو پارامتر را تعریف کردهایم:
function CreateCustomer(name: string, age?: number) {}
همانطور که مشاهده میکنید با افزودن علامت سوال بعد از نام پارامتر، توانستهایم آن را به صورت اختیاری تعریف کنیم. نکتهایی که در اینجا وجود دارد این است که تمامی پارامترهای optional، حتماً باید بعد از پارامترهای required تعریف شوند.
برای تعیین مقدار پیشفرض برای هر پارامتر نیز میتوانیم به اینصورت عمل کنیم:
function GetBookByTitle(title: string = 'C# 6.0 in a Nutshell') {}
default parameters در صورتیکه بعد از required parameters آورده شوند، به عنوان optional در نظر گرفته میشوند. یعنی در اینحالت لزومی به گذاشتن علامت سوال، بعد از نام پارامتر نیست. نکتهی قابل توجهایی که در استفاده از default parameters وجود دارد این است که علاوه بر رشتهها میتوان عبارات (expressions) را نیز به آنها اختصاص داد:
function GetBookByTitle(title: string = GetMostPopularBooks()) {}
Rest Parameters
rest parameters به شما این امکان را میدهند تا به تعداد نامحدودی پارامتر به یک تابع ارسال کنید:
function GetBooksReadForCust(name: string, ...bookIDs: number[]) {}
تابع فوق دو پارامتر را از ورودی دریافت میکند. پارامتر دوم این تابع به صورت rest تعریف شده است. یعنی برای پارامتر دوم میتوانیم هر تعداد پارامتری را به این تابع ارسال کنیم. همچنین برای نوع این پارامتر، یک آرایه از نوع number را تعیین کردهایم. یعنی پارامترهای دریافتی، درون یک آرایه از نوع number ذخیره خواهند شد. در ES 5 برای داشتن این چنین قابلیتی از شیء arguments استفاده میکردیم. یعنی تابع فوق را میبایستی اینگونه مینوشتیم:
function GetBooksReadForCust(name) { var bookIDs = []; for (var _i = 1; _i < arguments.length; _i++) { bookIDs[_i - 1] = arguments[_i]; } }
استفاده از this
درک this در جاوا اسکریپت، در ابتدا باعث مقداری سردرگمی میشود. یعنی مقدار آن در زمان فراخوانی تابع، ست خواهد شد. یعنی در هر بلاک از کد، وضعیتهای متفاوتی را ارائه میدهد. به عنوان مثال درون callback مربوط به تابع setInterval در تابع زیر میخواهیم به مقدار متغیر publishDate دسترسی داشته باشم:
function Book() { let self = this; self.publishDate = 2016; setInterval(function() { console.log(self.publishDate); }, 1000); }
همانطور که مشاهده میکنید برای دسترسی به این پراپرتی، مقدار this را درون یک متغیر با نام self، در ابتدا تعریف کردهایم. زیرا استفادهی مستقیم از this.publishDate درون callback به چیز دیگری اشاره میکند. این روش در ES 5 خیلی رایج است. اما با استفاده از Arrow Functions به راحتی میتوانیم به this در هر جایی دسترسی داشته باشیم. بنابراین کد فوق را میتوانیم به این صورت بازنویسی کنیم:
function Book() { this.publishDate = 2016; setInterval(() => { console.log(this.publishDate); }, 1000); }
در واقع Arrow Function در پشت صحنه کار capture کردن this را برایمان انجام خواهد داد.
Function overloads
قابلیت function overloading در بیشتر typed languageها در دسترس میباشد. همانطور که میدانید این قابلیت جهت تعریف امضاءهای مختلف برای یک تابع استفاده میشود. یعنی ایجاد توابعی با یک نام، اما با انواع متفاوت. از آنجائیکه TypeScript به جاوا اسکریپت کامپایل میشود، در نتیجه جاوا اسکریپت فاقد نوع (type) است. پس در زمان کامپایل نوعها برداشته خواهند شد. بنابراین داشتن توابعی همنام باعث بروز مشکلاتی خواهد شد. برای داشتن نسخههای مختلفی از یک تابع میتوانیم تعاریف موردنیازمان را ارائه داده، اما تنها یک پیادهسازی داشته باشیم. برای مثال میخواهیم یک overload دیگر برای تابع زیر داشته باشیم:
function GetTitles(author: string) : string[];
تابع فوق یک رشته را از ورودی دریافت کرده و در نهایت یک آرایه از رشتهها را بر میگرداند. برای overload دیگر این تابع میخواهیم به جای دریافت رشته، یک boolean از ورودی دریافت کنیم:
function GetTitles(available: boolean) : string[];
همانطور که مشاهده میکنید، هیچکدام از overloadهای فوق پیادهسازیایی ندارند. در واقع تا اینجا به TypeScript گفتهایم که نیاز به دو نسخه از تابع GetTitles خواهیم داشت. اکنون میتوانیم یک پیادهسازی کلی برای دو overload فوق داشته باشیم:
function GetTitles(bookProperty: any) : string[] { if(typeof bookProperty == 'string') { // some code } else if (typeof bookProperty == 'boolean') { // some code } return result; }
همانطور که عنوان شد، تنها پیادهسازی فوق را برای تمامی overloadها خواهیم داشت. در نتیجه اینبار نوع پارامتر ورودی را any تعریف کردهایم. سپس درون بدنهی تابع، نوع پراپرتی را توسط typeof تشخیص دادهایم. بنابراین برای فراخوانی هر یک از overloadها، میتوانیم کدهای خاصی را اجرا کنیم.
تعدادی از فناوریهایی که توسط این کتابخانه پشتیبانی میشوند در زیر آمده است:
Web Service: این فناوری اجازهی ارسال و دریافت پیامهای تحت شبکه را به خصوص بر روی اینترنت، فراهم میکند و باعث ارتباط جامعتر بین برنامهها و فناوریهای مختلف میگردد. در انواع جدیدتر WCF و Web Api نیز به بازار ارائه شدهاند.
webform و MVC : فناوریهای تحت وب که باعث سهولت در ساخت وب سایتها میشوند که وب فرم رفته رفته به سمت منسوخ شدن پیش میرود و در صورتی که قصد دارید طراحی وب را آغاز کنید توصیه میکنم از همان اول به سمت MVC بروید.
Rich Windows GUI Application : برای سهولت در ایجاد برنامههای تحت وب حالا چه با فناوری WPF یا فناوری قدیمی و البته منسوخ شده Windows Form.
Windows Console Application: برای ایجاد برنامههای ساده و بدون رابط گرافیکی.
Windows Services: شما میتوانید یک یا چند سرویس تحت ویندوز را که توسط Service Control Manager یا به اختصار SCM کنترل میشوند، تولید کنید.
Database stored Procedure: نوشتن stored procedure بر روی دیتابیسهایی چون sql server و اوراکل و ... توسط فریم ورک دات نت مهیاست.
Component Libraray: ساخت اسمبلیهای واحدی که میتوانند با انواع مختلفی از موارد بالا ارتباط برقرار کنند.
Portable Class Libary : این نوع پروژهها شما را قادر میسازد تا کلاسهایی با قابلیت انتقال پذیری برای استفاده در سیلور لایت، ویندوز فون و ایکس باکس و فروشگاه ویندوز و ... تولید کنید.
ازآنجا که یک کتابخانه شامل زیادی نوع میگردد سعی شده است گروه بندیهای مختلفی از آن در قالبی به اسم فضای نام namespace تقسیم بندی گردند که شما آشنایی با آنها دارید. به همین جهت فقط تصویر زیر را که نمایشی از فضای نامهای اساسی و مشترک و پرکاربرد هستند، قرار میدهم.
در CLR مفهومی به نام Common Type System یا CTS وجود دارد که توضیح میدهد نوعها باید چگونه تعریف شوند و چگونه باید رفتار کنند که این قوانین از آنجایی که در ریشهی CLR نهفته است، بین تمامی زبانهای دات نت مشترک میباشد. تعدادی از مشخصات این CTS در زیر آورده شده است ولی در آینده بررسی بیشتری روی آنان خواهیم داشت:
- فیلد
- متد
- پراپرتی
- رویدادها
CTS همچنین شامل قوانین زیادی در مورد وضعیت کپسوله سازی برای اعضای یک نوع دارد:
- private
- public
- Family یا در زبانهایی مثل سی ++ و سی شارپ با نام protected شناخته میشود.
- family and assembly: این هم مثل بالایی است ولی کلاس مشتق شده باید در همان اسمبلی باشد. در زبانهایی چون سی شارپ و ویژوال بیسیک، چنین امکانی پیاده سازی نشدهاست و دسترسی به آن ممکن نیست ولی در IL Assembly چنین قابلیتی وجود دارد.
- Assembly یا در بعضی زبانها به نام internal شناخته میشود.
- Family Or Assembly: که در سی شارپ با نوع Protected internal شناخته میشود. در این وضعیت هر عضوی در هر اسمبلی قابل ارث بری است و یک عضو فقط میتواند در همان اسمبلی مورد استفاده قرار بگیرد.
موارد دیگری که تحت قوانین CTS هستند مفاهیم ارث بری، متدهای مجازی، عمر اشیاء و .. است.
یکی دیگر از ویژگیهای CTS این است که همهی نوعها از نوع شیء Object که در فضای نام system قرار دارد ارث بری کردهاند. به همین دلیل همهی نوعها حداقل قابلیتهایی را که یک نوع object ارئه میدهد، دارند که به شرح زیر هستند:
- مقایسهی دو شیء از لحاظ برابری.
- به دست آوردن هش کد برای هر نمونه از یک شیء
- ارائهای از وضعیت شیء به صورت رشته ای
- دریافت نوع شیء جاری
وجود COMها به دلیل ایجاد اشیاء در یک زبان متفاوت بود تا با زبان دیگر ارتباط برقرار کنند. در طرف دیگر CLR هم بین زبانهای برنامه نویسی یکپارچگی ایجاد کرده است. یکپارچگی زبانهای برنامه نویسی علل زیادی دارند. اول اینکه رسیدن به هدف یا یک الگوریتم خاص در زبان دیگر راحتتر از زبان پایه پروژه است. دوم در یک کار تیمی که افراد مختلف با دانش متفاوتی حضور دارند و ممکن است زیان هر یک متفاوت باشند.
برای ایجاد این یکپارچگی، مایکروسافت سیستم CLS یا Common Language Specification را راه اندازی کرد. این سیستم برای تولیدکنندگان کامپایلرها جزئیاتی را تعریف میکند که کامپایلر آنها را باید با حداقل ویژگیهای تعریف شدهی CLR، پشتیبانی کند.
CLR/CTS مجموعهای از ویژگیها را شامل میشود و گفتیم که هر زبانی بسیاری از این ویژگیها را پشتیبانی میکند ولی نه کامل. به عنوان مثال برنامه نویسی که قصد کرده از IL Assembly استفاده کند، قادر است از تمامی این ویژگیهایی که CLR/CTS ارائه میدهند، استفاده کند ولی تعدادی دیگر از زبانها مثل سی شارپ و فورترن و ویژوال بیسیک تنها بخشی از آن را استفاده میکنند و CLS حداقل ویژگی که بین همه این زبانها مشترک است را ارائه میکند.
شکل زیر را نگاه کنید:
یعنی
اگر شما دارید نوع جدیدی را در یک زبان ایجاد میکنید که قصد دارید در یک
زبان دیگر استفاده شود، نباید از امتیازات ویژهای که آن زبان در اختیار شما میگذارد و به بیان بهتر CLS آنها را پشتیبانی نمیکند، استفاده کنید؛ چرا
که کد شما ممکن است در زبان دیگر مورد استفاده قرار نگیرد.
using System; // Tell compiler to check for CLS compliance [assembly: CLSCompliant(true)] namespace SomeLibrary { // Warnings appear because the class is public public sealed class SomeLibraryType { // Warning: Return type of 'SomeLibrary.SomeLibraryType.Abc()' // is not CLScompliant public UInt32 Abc() { return 0; } // Warning: Identifier 'SomeLibrary.SomeLibraryType.abc()' // differing only in case is not CLScompliant public void abc() { } // No warning: this method is private private UInt32 ABC() { return 0; } } }
دومین اخطار اینکه دو متد یکسان وجود دارند که در حروف بزرگ و کوچک تفاوت دارند. ولی زبان هایی چون ویژوال بیسیک نمیتوانند تفاوتی بین دو متد abc و ABC بیابند.
نکتهی جالب اینکه اگر شما کلمه public را از جلوی نام کلاس بردارید تمامی این اخطارها لغو میشود. به این خاطر که اینها اشیای داخلی آن اسمبلی شناخته شده و قرار نیست از بیرون به آن دسترسی صورت بگیرد. عضو خصوصی کد بالا را ببینید؛ کامنت بالای آن میگوید که چون خصوصی است هشداری نمیگیرد، چون قرار نیست در زبان مقصد از آن به طور مستقیم استفاده کند.
برای دیدن قوانین CLS به این صفحه مراجعه فرمایید.
در بالا در مورد یکپارچگی و سازگاری کدهای مدیریت شده توسط CLS صحبت کردیم ولی در مورد ارتباط با کدهای مدیریت نشده چطور؟
مایکروسافت موقعیکه CLR را ارئه کرد، متوجه این قضیه بود که بسیاری از شرکتها توانایی اینکه کدهای خودشون را مجددا طراحی و پیاده سازی کنند، ندارند و خوب، سورسهای مدیریت نشدهی زیادی هم موجود هست که توسعه دهندگان علاقه زیادی به استفاده از آنها دارند. در نتیجه مایکروسافت طرحی را ریخت که CLR هر دو قسمت کدهای مدیریت شده و نشده را پشتیبانی کند. دو نمونه از این پشتیبانی را در زیر بیان میکنیم:
یک. کدهای مدیریت شده میتوانند توابع مدیریت شده را در قالب یک dll صدا زده و از آنها استفاده کنند.
دو. کدهای مدیریت شده میتوانند از کامپوننتهای COM استفاده کنند: بسیاری از شرکتها از قبل بسیاری از کامپوننتهای COM را ایجاد کرده بودند که کدهای مدیریت شده با راحتی با آنها ارتباط برقرار میکنند. ولی اگر دوست دارید روی آنها کنترل بیشتری داشته باشید و آن کدها را به معادل CLR تبدیل کنید؛ میتوانید از ابزار کمکی که مایکروسافت همراه فریم ورک دات نت ارائه کرده است استفاده کنید. نام این ابزار TLBIMP.exe میباشد که از Type Library Importer گرفته شده است.
سه. اگر کدهای مدیریت نشدهی زیادتری دارید شاید راحتتر باشد که برعکس کار کنید و کدهای مدیریت شده را در در یک برنامهی مدیریت نشده اجرا کنید. این کدها میتوانند برای مثال به یک Activex یا shell Extension تبدیل شده و مورد استفاده قرار گیرند. ابزارهای TLBEXP .exe و RegAsm .exe برای این منظور به همراه فریم ورک دات نت عرضه شده اند.
سورس کد Type Library Importer را میتوانید در کدپلکس بیابید.
در ویندوز 8 به بعد مایکروسافت API جدید را تحت عنوان WinsowsRuntime یا winRT ارائه کرده است . این api یک سیستم داخلی را از طریق کامپوننتهای com ایجاد کرده و به جای استفاده از فایلهای کتابخانهای، کامپوننتها api هایشان را از طریق متادیتاهایی بر اساس استاندارد ECMA که توسط تیم دات نت طراحی شده است معرفی میکنند.
زیبایی این روش اینست که کد نوشته شده در زبانهای دات نت میتواند به طور مداوم با apiهای winrt ارتباط برقرار کند. یعنی همهی کارها توسط CLR انجام میگیرد بدون اینکه لازم باشد از ابزار اضافی استفاده کنید. در آینده در مورد winRT بیشتر صحبت میکنیم.
سخن پایانی: ممنون از دوستان عزیز بابت پیگیری مطالب تا بدینجا. تا این قسمت فصل اول کتاب با عنوان اصول اولیه CLR بخش اول مدل اجرای CLR به پایان رسید.
ادامهی مطالب بعد از تکمیل هر بخش در دسترس دوستان قرار خواهد گرفت.
الف) مقیاس پذیری سمت سرور
در اعمال سمت سرور متداول، تردهای متعددی جهت پردازش درخواستهای کلاینتها تدارک دیده میشوند. هر زمانیکه یکی از این تردها، یک عملیات blocking را انجام میدهد (مانند دسترسی به شبکه یا اعمال I/O)، ترد مرتبط با آن تا پایان کار این عملیات معطل خواهد شد. با بالا رفتن تعداد کاربران یک برنامه و در نتیجه بیشتر شدن تعداد درخواستهایی که سرور باید پردازش کند، تعداد تردهای معطل مانده نیز به همین ترتیب بیشتر خواهند شد. مشکل اصلی اینجا است که نمونه سازی تردها بسیار هزینه بر است (با اختصاص 1MB of virtual memory space) و منابع سرور محدود. با زیاد شدن تعداد تردهای معطل اعمال I/O یا شبکه، سرور مجبور خواهد شد بجای استفاده مجدد از تردهای موجود، تردهای جدیدی را ایجاد کند. همین مساله سبب بالا رفتن بیش از حد مصرف منابع و حافظه برنامه میگردد. یکی از روشهای رفع این مشکل بدون نیاز به بهبودهای سخت افزاری، تبدیل اعمال blocking نامبرده شده به نمونههای non-blocking است. به این ترتیب ترد پردازش کنندهی این اعمال Async بلافاصله آزاد شده و سرور میتواند از آن جهت پردازش درخواست دیگری استفاده کند؛ بجای اینکه ترد جدیدی را وهله سازی نماید.
ب) بالا بردن پاسخ دهی کلاینتها
کلاینتها نیز اگر مدام درخواستهای blocking را به سرور جهت دریافت پاسخی ارسال کنند، به زودی به یک رابط کاربری غیرپاسخگو خواهند رسید. برای رفع این مشکل نیز میتوان از توانمندیهای Async دات نت 4.5 جهت آزاد سازی ترد اصلی برنامه یا همان ترد UI استفاده کرد.
و ... تمام اینها یک شرط را دارند. نیاز است یک چنین API خاصی که اعمال Async واقعی را پشتیبانی میکنند، فراهم شده باشد. بنابراین صرفا وجود متد Task.Run، به معنای اجرای واقعی Async یک متد خاص نیست. برای این منظور ADO.NET 4.5 به همراه متدهای Async ویژه کار با بانکهای اطلاعاتی است و پس از آن Entity framework 6 از این زیر ساخت استفاده کردهاست که در ادامه جزئیات آنرا بررسی خواهیم کرد.
پیشنیازها
برای کار با امکانات جدید Async موجود در EF 6 نیاز است از VS 2012 به بعد که به همراه کامپایلری است که واژههای کلیدی async و await را پشتیبانی میکند و همچنین دات نت 4.5 استفاده کرد. چون ADO.NET 4.5 اعمال async واقعی را پشتیبانی میکند، دات نت 4 در اینجا قابل استفاده نخواهد بود.
متدهای الحاقی جدید Async در EF 6.x
جهت متدهای الحاقی متداول EF مانند ToList، Max، Min و غیره، نمونههای Async آنها نیز اضافه شدهاند:
QueryableExtensions: AllAsync AnyAsync AverageAsync ContainsAsync CountAsync FirstAsync FirstOrDefaultAsync ForEachAsync LoadAsync LongCountAsync MaxAsync MinAsync SingleAsync SingleOrDefaultAsync SumAsync ToArrayAsync ToDictionaryAsync ToListAsync DbSet: FindAsync DbContext: SaveChangesAsync Database: ExecuteSqlCommandAsync
چند مثال
فرض کنید، مدلهای برنامه، رابطهی one-to-many ذیل را بین یک کاربر و مقالات او دارند:
public class User { public int Id { get; set; } public string Name { get; set; } public virtual ICollection<BlogPost> BlogPosts { get; set; } } public class BlogPost { public int Id { get; set; } public string Title { get; set; } public string Content { get; set; } [ForeignKey("UserId")] public virtual User User { get; set; } public int UserId { get; set; } }
public class MyContext : DbContext { public DbSet<User> Users { get; set; } public DbSet<BlogPost> BlogPosts { get; set; } public MyContext() : base("Connection1") { this.Database.Log = sql => Console.Write(sql); } }
private async Task<User> addUserAsync(CancellationToken cancellationToken = default(CancellationToken)) { using (var context = new MyContext()) { var user = context.Users.Add(new User { Name = "Vahid" }); context.BlogPosts.Add(new BlogPost { Content = "Test", Title = "Test", User = user }); await context.SaveChangesAsync(cancellationToken); return user; } }
چند نکته جهت یادآوری مباحث Async
- به امضای متد واژهی کلیدی async اضافه شدهاست، زیرا در بدنهی آن از کلمهی کلیدی await استفاده کردهایم (لازم و ملزوم هستند).
- به انتهای نام متد، کلمهی Async اضافه شدهاست. این مورد ضروری نیست؛ اما به یک استاندارد و قرارداد تبدیل شدهاست.
- مدل Async دات نت 4.5 مبتنی بر Taskها است. به همین جهت اینبار خروجیهای توابع نیاز است از نوع Task باشند و آرگومان جنریک آنها، بیانگر نوع مقداری که باز میگردانند.
- تمام متدهای الحاقی جدیدی که نامبرده شدند، دارای پارامتر اختیاری لغو عملیات نیز هستند. این مورد را با مقدار دهی cancellationToken در کدهای فوق ملاحظه میکنید.
نمونهای از نحوهی مقدار دهی این پارامتر در ASP.NET MVC به صورت زیر میتواند باشد:
[AsyncTimeout(8000)] public async Task<ActionResult> Index(CancellationToken cancellationToken)
- برای اجرا و دریافت نتیجهی متدهای Async دار EF، نیاز است از واژهی کلیدی await استفاده گردد.
استفاده کننده نیز میتواند متد addUserAsync را به صورت زیر فراخوانی کند:
var user = await addUserAsync(); Console.WriteLine("user id: {0}", user.Id);
شبیه به همین اعمال را نیز جهت به روز رسانی و یا حذف اطلاعات خواهیم داشت:
private async Task<User> updateAsync(CancellationToken cancellationToken = default(CancellationToken)) { using (var context = new MyContext()) { var user1 = await context.Users.FindAsync(cancellationToken, 1); if (user1 != null) user1.Name = "Vahid N."; await context.SaveChangesAsync(cancellationToken); return user1; } } private async Task<int> deleteAsync(CancellationToken cancellationToken = default(CancellationToken)) { using (var context = new MyContext()) { var user1 = await context.Users.FindAsync(cancellationToken, 1); if (user1 != null) context.Users.Remove(user1); return await context.SaveChangesAsync(cancellationToken); } }
کدهای Async تقلبی!
به قطعه کد ذیل دقت کنید:
public async Task<List<TEntity>> GetAllAsync() { return await Task.Run(() => _tEntities.ToList()); }
به این نوع متدها که از Task.Run برای فراخوانی متدهای همزمان قدیمی مانند ToList جهت Async جلوه دادن آنها استفاده میشود، کدهای Async تقلبی میگویند! این عملیات هر چند در یک ترد دیگر انجام میشود اما هم سربار ایجاد یک ترد جدید را به همراه دارد و هم عملیات ToList آن کاملا blocking است.
معادل صحیح Async واقعی این عملیات را در ذیل مشاهده میکنید:
private async Task<List<User>> getUsersAsync(CancellationToken cancellationToken = default(CancellationToken)) { using (var context = new MyContext()) { return await context.Users.ToListAsync(cancellationToken); } }
برای مثال پشت صحنهی متد الحاقی SaveChangesAsync به یک چنین متدی ختم میشود:
internal override async Task<long> ExecuteAsync( //... rowsAffected = await command.ExecuteNonQueryAsync(cancellationToken).ConfigureAwait(continueOnCapturedContext: false); //...
و یا برای شبیه سازی ToListAsync با ADO.NET 4.5 و استفاده از متدهای Async واقعی آن، به یک چنین کدهایی نیاز است:
var connectionString = "........"; var sql = @"......""; var users = new List<User>(); using (var cnx = new SqlConnection(connectionString)) { using (var cmd = new SqlCommand(sql, cnx)) { await cnx.OpenAsync(); using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection)) { while (await reader.ReadAsync()) { var user = new User { Id = reader.GetInt32(0), Name = reader.GetString(1), }; users.Add(user); } } } }
محدودیت پردازش موازی اعمال در EF
در متد ذیل، دو Task غیرهمزمان تعریف شدهاند و سپس با await Task.WhenAll درخواست اجرای همزمان و موازی آنها را کردهایم:
// multiple operations private static async Task loadAllAsync(CancellationToken cancellationToken = default(CancellationToken)) { using (var context = new MyContext()) { var task1 = context.Users.ToListAsync(cancellationToken); var task2 = context.BlogPosts.ToListAsync(cancellationToken); await Task.WhenAll(task1, task2); // use task1.Result } }
An unhandled exception of type 'System.NotSupportedException' occurred in mscorlib.dll Additional information: A second operation started on this context before a previous asynchronous operation completed. Use 'await' to ensure that any asynchronous operations have completed before calling another method on this context. Any instance members are not guaranteed to be thread safe.
چرا باید از ابزارهای Object relational Mapper یا به اختصار ORM استفاده کرد؟ در اینجا سخن در مورد ORM خاصی نیست. هدف تبلیغ یک محصول ویژه هم نمیباشد و یک بحث کلی مد نظر است.
کار ابزارهای ORM خواندن ساختار دیتابیس شما بوده و سپس ایجاد کلاسهایی بر اساس این ساختار ، برقراری ارتباط بین اشیاء ایجاد شده و جداول، ویووها، رویههای ذخیره شده و غیره میباشد. همچنین این ابزارها امکان تعریف روابط one-to-one, one-to-many, many-to-one, و many-to-many بین اشیاء را نیز بر اساس ساختار دیتابیس شما فراهم میکنند.
در ادامه به فواید استفاده از ORM ها خواهیم پرداخت:
الف) یک ابزار ORM زمان تحویل پروژه را کاهش میدهد
اولین و مهمترین دلیلی که بر اساس آن در یک پروژه، استفاده از ORM حائز اهمیت میشود، بحث بالا بردن سرعت برنامه نویسی و کاهش زمان تحویل پروژه به مشتری است. این کاهش زمان بسته به نوع پروژه بین 20 تا 50 درصد میتواند خود را بروز دهد.
بدیهی است ابزارهای ORM کار شگفت انگیزی را قرار نیست انجام دهند و شما میتوانید تمام آن عملیات را دستی هم به پایان رسانید؛ اما اجازه دهید یک مثال کوتاه را با هم مرور کنیم.
برای پیاده سازی یک برنامه متداول با حدود 15 تا 20 جدول، حدودا به 30 شیء برای مدل سازی سیستم نیاز خواهد بود و برنامه نویسی این مجموعه بین 5000 تا 10000 سطر کد را به خود اختصاص خواهد داد. بدیهی است برنامه نویسی و آزمایش این سیستم چندین هفته یا ماه به طول خواهد انجامید.
اما با استفاده از یک ORM ، عمده وقت شما به طراحی سیستم و ایجاد ارتباطات بین اشیاء و دیتابیس در طی یک تا دو روز صرف خواهد شد. ایجاد کد بر اساس این مجموعه و با کمک ابزارهای ORM ، آنی است و با چند کلیک صورت میگیرد.
ب) یک ابزار ORM کدی با طراحی بهتر را تولید میکند
ممکن است شما بگوئید که کد نویسی من بینظیر است و از من بهتر کسی را نمیتوانید پیدا کنید! به تمامی زوایای کار خود مسلطم و نیازی هم به اینگونه ابزارها ندارم!
عدهای از شما به طور قطع اینگونهاید؛ اما نه همه. در یک تیم متوسط، همه نوع برنامه نویس با سطوح مختلفی را میتوانید پیدا کنید و تمامی آنها برنامه نویسها و یا طراحهای آنچنان قابلی هم نیستند. بنابراین امکان رسیدن به کدهایی که مطابق اصول دقیق برنامه نویسی شیء گرا نیستند و در آنها الگوهای طراحی به خوبی رعایت نشده، بسیار محتمل است. همچنین در یک تیم زمانیکه از یک الگوی یکسان پیروی نمیشود، نتایج نهایی بسیار ناهماهنگ خواهند بود.
در مقابل استفاده از ORM های طراحی شده توسط برنامه نویسهای قابل (senior (architect level) engineers) ، کدهایی را بر اساس الگوهای استاندارد و پذیرفته شدهی شیءگرا تولید میکنند و همواره یک روند کاری مشخص و هماهنگ را در یک مجموعه به ارمغان خواهند آورد.
ج) نیازی نیست تا حتما یک متخصص دات نت فریم ورک باشید تا از یک ORM استفاده کنید
قسمت دسترسی به دادهها یکی از اجزای کلیدی کارآیی برنامه شما است. اگر طراحی و پیاده سازی آن ضعیف باشد، کل برنامه را زیر سؤال خواهد برد. برای طراحی و پیاده سازی دستی این قسمت از کار باید به قسمتهای بسیاری از مجموعهی دات نت فریم ورک مسلط بود. اما هنگام استفاده از یک ORM مهمترین موردی را که باید به آن تمرکز نمائید بحث طراحی منطقی کار است و ایجاد روابط بین اشیاء و دیتابیس و امثال آن. مابقی موارد توسط ORM انجام خواهد شد و همچنین میتوان مطمئن بود که پیاده سازی خودکار انجام شده این قسمتها، بر اساس الگوهای طراحی شیءگرا است.
د) هنگام استفاده از یک ابزار ORM ، مدت زمان آزمایش برنامه نیز کاهش مییابد
بدیهی است اگر قسمت دسترسی به دادهها را خودتان طراحی و پیاده سازی کرده باشید، زمان قابل توجهی را نیز باید به بررسی و آزمایش صحت عملکرد آن بپردازید و الزامی هم ندارد که این پیاده سازی مطابق بهترین تجربیات کاری موجود بوده باشد. اما هنگام استفاده از کدهای تولید شده توسط یک ابزار ORM میتوان مطمئن بود که کدهای تولیدی آن که بر اساس یک سری الگوی ویژه تولید میشوند، کاملا آزمایش شده هستند و همچنین صدها و یا هزارها نفر در دنیا هم اکنون دارند از این پایه در پروژههای موفق خود استفاده میکنند و همچنین بازخوردهای خود را نیز به تیم برنامه نویسی آن ابزار ORM ارائه میدهند و این مجموعه مرتبا در حال بهبود و به روز شدن است.
ه) استفاده از یک ابزار ORM ، کار برنامه نویسی شما را سادهتر میکند
توضیح این قسمت نیاز به ذکر یک مثال دارد. لطفا به مثال زیر دقت بفرمائید:
try {
Employees objInfo = new Employees();
EmployeesFactory objFactory = new EmployeesFactory();
objInfo.EmployeeID = EmployeeID;
objFactory.Load(objInfo);
// code here to use the "objInfo" object
}
catch(Exception ex) {
// code here to handle the exception
}
به نظر شما کار کردن با یک یا چند شیء تولید شده که نمایانگر ساختار دیتابیس شما هستند و با استفاده از اینترفیس عمومی آنها میتوان تمامی اعمال بارگذاری، درج و حذف و غیره را انجام داد، سادهتر است یا کار کردن با کوهی از دستورات ADO.Net ؟
برداشتی آزاد از Five Reasons for using an ORM Tool