آموزش نصب و تنظیم Nginx در لینوکس

وب سرور Nginx با ویژگی‌های منحصر به فرد خود، کاربردهای گسترده‌ای در زمینه های مختلف دارد. یکی از کاربردهای اصلی آن، میزبانی وب‌سایت های پربازدید است. Nginx می تواند ترافیک سنگین را به راحتی مدیریت کند و سرعت لود صفحات را افزایش دهد. در زمینه استریم ویدیویی و پخش محتوا، Nginx یک ابزار قدرتمند محسوب می شود. با قابلیت کش کردن محتوا و تحویل سریع ویدیو، Nginx  می تواند تجربه کاربری بهتری را برای مشاهده محتوای ویدیویی فراهم کند. با توجه به انعطاف پذیری و کارایی بالای Nginx، این وب سرور در زمینه‌های متنوعی از جمله وب‌سایت‌ها، سرویس‌های ابری، پلتفرم‌های استریم کاربرد گسترده‌ای دارد.

وب سرور Nginx چیست؟

آموزش نصب و تنظیم Nginx در لینوکس

در دنیای پرچالش وب امروز، یکی از مهمترین نیازها، مدیریت موثر ترافیک وب‌سایت‌ها و برنامه‌های مبتنی بر وب است. در این میان، وب سرور Nginx با ویژگی‌های منحصر به فرد خود، به یک گزینه محبوب و پرکاربرد تبدیل شده است. Nginx یک نرم‌افزار منبع باز (Open Source) و رایگان است که در سال 2004 توسط ایگور سیسوف، یک برنامه‌نویس روسی توسعه یافت. هدف اصلی آن، ایجاد یک وب سرور سبک، سریع و کارآمد بود که بتواند با ترافیک سنگین به خوبی کنار بیاید. یکی از ویژگی های برجسته Nginx، معماری رویداد محور و غیرمتمرکز آن است. این معماری باعث می شود که Nginx بتواند با مصرف منابع بسیار کمتر، ترافیک بیشتری را پردازش کند. در نتیجه، هزینه‌های میزبانی کاهش و کارایی سیستم افزایش می‌یابد. Nginx از امنیت قابل توجهی نیز برخوردار است. این وب سرور قادر است از وب‌سایت‌ها در برابر حملات متداول مانند حملات DDOS محافظت کند و همچنین می‌تواند ترافیک را رمزنگاری کند تا امنیت داده‌ها افزایش یابد. کاربرد گسترده Nginx در زمینه‌های مختلف از جمله میزبانی وب‌سایت‌های پربازدید، پلتفرم های استریم ویدیویی، سرویس‌های ابری و معماری‌های میکروسرویس، نشان دهنده قدرت و کارایی این وب سرور است. شرکت های بزرگی مانند Netflix ،Cloudflare و بسیاری دیگر، از Nginx برای ارائه خدمات وب خود استفاده می‌کنند. Nginx با ترکیبی از سرعت، کارایی، امنیت و انعطاف پذیری، به یکی از پرکاربردترین و محبوب‌ترین وب سرورهای دنیای امروز تبدیل شده است. این ابزار قدرتمند، راه را برای مدیریت موثر ترافیک وب و ارائه تجربه کاربری بهتر هموار می‌کند.

مزایا و معایب استفاده از Nginx

Nginx با مزایای قابل توجهی مانند کارایی بالا، امنیت و انعطاف‌پذیری همراه است. این ویژگی‌ها آن را به یک گزینه محبوب برای میزبانی وب‌سایت‌ها، برنامه‌های وب و سرویس‌های مختلف تبدیل کرده است. با این حال، معایبی نیز دارد که باید در نظر گرفته شوند. برخی از مزایای استفاده از Nginx عبارتند از:

  • کارایی و عملکرد بالا: Nginx با معماری رویداد محور (Event-driven architecture) و غیرمتمرکز خود، قادر است ترافیک سنگین را با مصرف منابع بسیار کم مدیریت کند. این امر باعث کاهش هزینه‌های میزبانی و افزایش سرعت لود صفحات می‌شود.
  • امنیت بالا: Nginx از امنیت قابل توجهی برخوردار است و می‌تواند از وب سایت‌ها در برابر حملات متداول مانند حملات DDOS محافظت کند. همچنین، قابلیت رمزگذاری ترافیک را نیز دارد تا داده‌ها به صورت امن انتقال یابند.
  • پشتیبانی از پروتکل‌های مختلف: Nginx می‌تواند از پروتکل‌های متنوعی مانند HTTP، HTTPS، SMTP، POP3 و IMAP پشتیبانی کند. این ویژگی آن را به یک گزینه ایده‌آل برای میزبانی انواع سرویس‌های وب تبدیل می‌کند.
  • جامعه فعال و پشتیبانی خوب: Nginx دارای یک جامعه فعال و پشتیبانی خوب است. این امر به معنای دسترسی به منابع، راهنماها و به‌روزرسانی‌های منظم است که می‌تواند استفاده از این وب سرور را آسان‌تر کند.

برخی از معایب استفاده از Nginx عبارتند از:

  • پیچیدگی تنظیمات: Nginx دارای یک ساختار پیچیده است و تنظیمات آن می‌تواند برای کاربران مبتدی سخت و چالش‌ برانگیز باشد. به همین دلیل کار کردن با آن ممکن است نیاز به یادگیری و تمرین زیاد داشته باشد.
  • محدودیت‌های ذاتی: Nginx برای پردازش برخی از زبان‌های برنامه‌نویسی مانند PHP و Python محدودیت‌هایی دارد. این امر ممکن است در برخی موارد، استفاده از وب سرورهای دیگر را ضروری کند.
  • مدیریت پیچیده: در محیط‌های بزرگ با تعداد زیادی سرور، مدیریت و نگهداری Nginx می‌تواند پیچیده شود و نیاز به ابزارها و فرایندهای خاصی داشته باشد.

نصب Nginx

قبل از شروع نصب، بهتر است مخازن نرم‌افزاری (Software Repository) سیستم خود را بروزرسانی کنید. این کار را می‌توانید با دستور زیر انجام دهید:

sudo apt update

پس از بروزرسانی مخازن نرم‌افزاری، می‌توانید Nginx را با دستور زیر نصب کنید:

sudo apt install nginx

این دستور، آخرین نسخه پایدار Nginx را از مخازن اوبونتو دریافت و نصب خواهد کرد.

پس از نصب موفق، وب سرور Nginx به صورت خودکار راه‌اندازی می‌شود. کاربران می‌توانند با دستور زیر از وضعیت آن اطلاع یابند:

sudo systemctl status nginx

این دستور، وضعیت فعلی سرویس Nginx را نمایش می‌دهد.

همچنین کاربران با استفاده از دستور زیر می توانند نسخه نصب شده NGINX را بررسی کنند:

nginx -v

پیکربندی فایروال

آموزش نصب و تنظیم Nginx در لینوکس

پس از نصب موفق Nginx در سیستم عامل اوبونتو، یکی از مراحل مهم و ضروری، تنظیم صحیح فایروال است. فایروال نقش حیاتی در محافظت از وب سرور شما در برابر تهدیدات امنیتی و حملات احتمالی دارد. اولین قدم در پیکربندی فایروال، نصب فایروال UFW  است. این فایروال به صورت پیش‌فرض در اوبونتو نصب نشده است، بنابراین باید آن را با دستور زیر نصب کنید:

sudo apt-get install ufw

پس از نصب UFW، باید به عبور ترافیک HTTP (پورت 80) و HTTPS (پورت 443) از فایروال اجازه دهید. این کار را می‌توانید با دستو زیر انجام دهید:

sudo ufw allow Nginx ‘HTTP’

sudo ufw allow ‘Nginx HTTPS’

sudo ufw allow ‘Nginx Full’

این دستورات، قواعد جدیدی در فایروال ایجاد می‌کنند که به Nginx اجازه می‌دهند تا از پورت‌های 80 و 443 ترافیک را دریافت کند. پس از وارد کردن دستورات بالا، باید سرویس Nginx را با استفاده از دستور زیر راه‌اندازی کنیم:

sudo systemctl start nginx

کاربران ممکن است بخواهند تا سرویس Nginx در هنگام بوت شدن سیستم به طور خودکار راه‌اندازی شود، این ویژگی را با استفاده از دستور زیر می‌توانند فعال کنند:

sudo systemctl enable nginx

پس از تنظیم قوانین مورد نیاز، شما می‌توانید فایروال UFW را با دستور زیر فعال کنید:

sudo ufw enable

این دستور، فایروال را فعال کرده و تنها به ترافیک مجاز اجازه عبور می‌دهد.

جهت اطمینان از تنظیم صحیح فایروال، می‌توانید وضعیت آن را با دستور زیر بررسی کنید:

sudo ufw status

این دستور، لیستی از قواعد فعال در فایروال را نمایش می‌دهد.

بررسی وضعیت Nginx

پس از نصب Nginx در سیستم عامل اوبونتو، باید بتوانید وضعیت آن را بررسی و کنترل کنید. این امر به شما این امکان را می‌دهد تا از عملکرد صحیح وب سرور خود اطمینان حاصل کنید، مشکلات احتمالی را شناسایی کرده و اقدامات لازم را برای رفع آنها انجام دهید. یکی از روش‌های ساده برای بررسی وضعیت Nginx، استفاده از دستور systemctl است. با استفاده از دستور زیر می‌توانید ببینید که آیا سرویس Nginx در حال اجرا است یا خیر:

sudo systemctl status nginx

لاگ‌های Nginx می‌توانند اطلاعات ارزشمندی در مورد عملکرد وب سرور، خطاها و رفتار کاربران به شما ارائه دهند. لاگ‌های Nginx به طور پیش‌فرض در مسیرهای زیر قرار دارند:

Access Log: /var/log/nginx/access.log

Error Log: /var/log/nginx/error.log

می‌توانید با دستورات زیر، محتویات این لاگ‌ها را مشاهده کنید:

sudo tail -n 20 /var/log/nginx/access.log

sudo tail -n 20 /var/log/nginx/error.log

این دستورات، ۲۰ خط آخر لاگ‌ها را نمایش می‌دهند تا بتوانید رفتار اخیر وب سرور را بررسی کنید.

مدیریت Nginx

برای بهره‌گیری حداکثری از توانایی‌های Nginx، نیاز به مدیریت صحیح و کنترل کامل بر آن دارید. مدیریت صحیح Nginx در اوبونتو، به شما این امکان را می‌دهد تا از تمام توانایی‌های این وب سرور قدرتمند بهره‌مند شوید. با داشتن کنترل کامل بر سرویس، فایل‌های پیکربندی، ماژول‌ها و ابزارهای مدیریت، می‌توانید Nginx را برای نیازهای خاص خود تنظیم کرده و عملکرد آن را بهینه کنید. یکی از روش‌های اصلی مدیریت Nginx در اوبونتو، استفاده از دستور systemctl است. این دستور به شما این اجازه را می‌دهد تا سرویس Nginx خود را راه‌اندازی، متوقف و یا راه‌اندازی مجدد کنید. برای مثال:

  • راه‌اندازی :   sudo systemctl start nginx
  • توقف : sudo systemctl stop nginx
  • راه‌اندازی مجدد : sudo systemctl restart nginx
  • بررسی وضعیت : sudo systemctl status nginx

تفاوت Stored Procedure و Function در SQL Server

Stored Procedure های اشیایی هستند که در اولین بار کامپایل شده و  فرمت آن ذخیره می شود (کد کامپایل شده) و در دفعات بعدی میتوان آن را فراخوانی کرد و این مورد خود باعث افزایش سرعت اجرای آن می شود . اما Function  ها  در هر بار فراخوانی آنها ، ابتدا می بایست کامپایل شوند  و سپس اجرا میشوند .

تفاوت های پایه:

Function ها حتما باید مقداری را به عنوان خروجی برگردانند در صورتی که در Stored Procedure ها اختیاری می باشدProcedure  می تواند صفر یا n مقدار برگرداند.

Function  های فقط می توانند پارامترهای ورودی داشته باشند در صورتی که Stored Procedure ها می توانند پارامتر های Input و Output  داشته باشند .

Function  ها میتوانند از داخل یک Stored Procedure فراخوانی شوند در حالی که نمیتوان در داخل یک Function اقدام به فراخوانی یک Procedure کرد .

تفاوت های پیشرفته :

Stored Procedure  ها اجازه استفاده از دستور SELECT را به خوبی می دهند و همچنین دستورات (DML) insert,update,delete  در حالیکه Function ها فقط اجازه استفاده از دستور SELECT را دارند .

Stored Procedure  ها نمی توانند در داخل دستورات SELECT استفاده شوند درحالیکه Function می تواند در داخل دستورات SELECT جاسازی شود .

Stored Procedure  ها نمی توانند در هر جای  دستورات SQL  استفاده شوند ، برای نمونه نمی توانند در قسمت های WHERE/HAVING,SELECT  استفاده شوند در حالیکه این محدودیت برای Function وجود ندارد .

می توان در داخل Stored Procedure ها استثنا ها را با استفاده از بلوک های try-catch مدیریت کرد در حالیکه در داخل Function نمی توان بلوک های try-catch را مورد استفاده قرار داد .

Function ها می توانند یک Table را در خروجی برگردانند که این Table میتواند در داخل دستورات Join با جداول دیگر مورد استفاده قرار گیرد .

مهمترین ویژگی Stored Procedure ها نسبت به Function ها نگهداری و قابلیت استفاده مجدد execution plan می باشد درحالیکه برای Function ها هربار کامپایل می شود .

نحوه ساخت Function در Sql Server :

میتوان مطابق با شکل زیر نیز فانکشن را ایجاد نمود

تفاوت Stored Procedure و Function در SQL Server

نحوه ساخت Stored Procedure در Sql Server :

تفاوت Stored Procedure و Function در SQL Server

پارتیشن بندی (Partition) در Sql Server

یکی از قابلیت های بانک اطلاعاتی در SQL Server پارتیشن بندی می باشد. قابلیت پارتیشن بندی به SQL در سال 2005 اضافه گردید و در نسخه های بعدی که به کاربران معرفی گردید بهبود و گسترش یافت.

با استفاده از این قابلیت این امکان وجود دارد که جداولی که حجم داده هایش بسیار زیاد است به ساختارهای جداگانه تقسیم شود. به کد نویسی سمت Application به هیچ عنوان برای برای استفاده از قابلیت پارتیشن بندی SQL نیازی وجود ندارد.

ما در این مقاله پارتیشن بندی در SQL سرور را معرفی خواهیم کرد. شما در پایان این مقاله خواهید فهمید که چرا باید پارتیشن بندی را انجام دهیم و مراحل پارتیشن بندی در SQL سرور چگونه است.


پارتیشن بندی چیست ؟

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

هدف اصلی از پارتیشن بندی کمک به حفظ جداول بزرگ و کاهش زمان پاسخ کلی برای خواندن و بارگذاری داده ها برای عملکردهای خاص SQL است.


چرا باید پایگاه داده را پارتیشن بندی کنیم ؟

با تقسیم بندی داده ها، می توان انبوهی از داده ها را به پارتیشن های كوچكتر و در نتیجه با مدیریت بهتر، می توان به مسائل مربوط به پشتیبانی از جداول بزرگ بهتر پاسخ داد. پارتیشن بندی داده ها همچنین منجر به بارگذاری سریعتر داده ها، نظارت آسان بر داده های قدیمی و بازیابی اطلاعات می شود.


پارتیشن بندی در SQL Server

SQL Server از پارتیشن بندی جدول و فهرست پشتیبانی می کند. داده های جداول و نمایه های تقسیم شده به واحدهایی تقسیم می شوند که به صورت اختیاری ممکن است در بیش از یک گروه در پایگاه داده پخش شوند. داده ها به صورت افقی تقسیم می شوند ، بنابراین گروه های ردیف به صورت جداگانه تقسیم می شوند


سطوح مختلف پارتیشن بندی

پارتیشن بندی در SQL شامل سه سطح می باشد. در سطح اول ما پارتیشن بندی را در سطح داده، سپس در تابع پارتیشن و در سطح سوم نیز در محل ذخیره سازی ما پارتیشن بندی را انجام می دهیم. ما در ادامه این سه سطح را به شما معرفی خواهیم کرد.

•    سطح 1: داده؛ در سطح اول داده هایی که عمل پارتیشن بندی بر روی آنها رخ می دهد.

•    سطح 2: Partition Function؛ در سطح دوم قسمتی است که پارتیشن بندی را مشخص می نماید و تابع پارتیشن، نام دارد..

•    سطح 3: Partition Scheme: در سطح سوم محلی که ذخیره سازی پارتیشن ها را معلوم می کند.


مراحل پارتیشن بندی در SQL Server

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


دیدگاه های مختلف پارتیشن بندی :

  • از دید پیاده ساز
  • از دید مدیر بانک اطلاعاتی


مراحل پارتیشن بندی در SQL Server از دید Developer

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


مرحله 1: مشخص کردن کلید پارتیشن با  Partition Key

یکی از مهمترین بخش های پارتیشن بندی مشخص کردن Partition Key می باشد. در اینجا باید به عنوان کلید پارتیشن بندی شما فیلدی را انتخاب کنید. انتخاب شما باید بر اساس جستجوی بیشتر باشد. 

برای مثال ما سیستم مالی را در آورده ایم. ایجاد سند یکی از  فرم های بسیار مهم این بخش می باشد. در جدولی که مربوط به این فرم است، در جداول آیا انتخاب تاریخ می تواند گزینه مناسبی  برای Partition Key در نظر گرفته شود؟

در این انتخاب نکته ی دیگری که باید شما در نظر بگیرید این است از اینجا به بعد برای داشتن بهترین کارایی، اگر تاریخ را به عنوان Partition Key انتخاب کرده اید، در تمام Query جستجو باید حتما تاریخ را داشته باشید.
 بنابراین ممکن است که با یک سیاست خاص مجبور باشید متقاعد کنید کاربران سیستم را که در فرم های جستجو حتماً فیلد تاریخ را تنظیم نمایند.


مرحله 2: تعیین تعداد پارتیشن ها

باید یک تخمین درست با در نظر گرفتن حجم داده و میزان پیشرفت از تعداد پارتیشن های مورد نیاز داشته باشید. به عنوان مثال اگر تاریخ اساس کلید پارتیشن بندی شما است، بین ماه و سال باید شما انتخاب بعدی خود را داشته باشید؟ مثلاً اگر در یک ماه تعداد رکوردهای شما بالای 30.000.000 باشد، براساس ماه پارتیشن بندی گزینه بهتری می تواند باشد.

توجه داشته باشید: زمان جستجو نیز هر چه تعداد رکورد پارتیشن بیشتر باشد، بیشتر خواهد شد، حتما دقت داشته باشید که تعداد پارتیشن ها را به درستی انتخاب کرده اید.

مراحل پارتیشن بندی در SQL server از دید مدیر بانک اطلاعاتی

حالا که به خوبی کلید و تعداد پارتیشن ها را مشخص کردید نوبت به بررسی توسط مدیر بانک اطلاعاتی رسیده است. مراحل پارتیشن بندی در SQL از دید مدیر بانک اطلاعاتی شامل دو مرحله ایجاد Filegroup و Partition Function می باشد.


مرحله 1: ایجاد Filegroup

یک Filegroup را می توان به ازای هر پارتیشن ایجاد کرد. این امکان وجود دارد که چند پارتیشن و یا حتی تمام پارتیشن ها را در یک Filegroup  قرار دهیم.


مرحله 2: مشخص کردن Partition function

محل قرار گیری رکوردها در SQL را می توان با استفاده از Partition Function مشخص کرد. آنها را می توان در یک Partition مشخص نمود. نقاط مرزی که برای تقسیم داده ها از طریق Partition Function مشخص می شود را نیز ایجاد کرد.

حالا که با مفهوم پارتیشن بندی، سطوح و مراحل آن آشنا شدیم در ادامه مقاله با آموزش دو مبحث کاربردی پارتیشن بندی در SQL با ما همراه بشید.

  1.  ایجاد پارتیشن به صورت ویزاردی زمانی که پارتیش را بخواهیم روی کلید اصلی جدول ایجاد کنیم

در این قسمت می خواهیم عملیات پارتیشن بندی را به صورت ویزادی بر روی فیلد کلاستر جدول tblNew انجام دهیم.

لازم به ذکر است که چهار فایل گروپ به این دیتابیس به نام های FG1,FG2,FG3,FG4 اضافه کنید.

پارتیشن بندی (Partition) در Sql Server
پارتیشن بندی (Partition) در Sql Server
  1. در این مرحله Filegroup های مورد نظر  (چهار Filegroup)  را ایجاد می کنیم. 
پارتیشن بندی (Partition) در Sql Server
پارتیشن بندی (Partition) در Sql Server
  •  در این مرحله بر روی جدولی که می خواهیم پارتیشن شود، کلیک راست کرده و گزینه Storage و سپس گزینه Create Partition را کلیک می کنیم.
پارتیشن بندی (Partition) در Sql Server
  • در این مرحله پنجره خوش آمد گویی نمایان می شود.
پارتیشن بندی (Partition) در Sql Server
  • در این مرحله مشخص می کنیم که بر روی کدام ستون می خواهیم عمل پارتیشن صورت پذیرد (نام ستون پارتیشن را وارد می کنیم).
پارتیشن بندی (Partition) در Sql Server
  • در این مرحله نام پارتیشن فانکشن مورد نظرمان را وارد می کنیم.
پارتیشن بندی (Partition) در Sql Server
  • در این مرحله نام Partition Scheme خود را می دهیم.
پارتیشن بندی (Partition) در Sql Server
  • حال در اینجا :
پارتیشن بندی (Partition) در Sql Server
  • در این مرحله یا می توانیم اسکریپت بگریم (Create Script) و یا اینکه بلافاصله اقدام به ایجاد پارتیشن کنیمRun Immediately  و یا اینکه به صورت یک فایل آن اسکریپ را ذخیره نماییم(Save Script) و یا اینکه در اسکریپت را در حافظه ذخیره کنیم(Script to Clipboard).
پارتیشن بندی (Partition) در Sql Server
  • خلاصه ای از تنظیماتی که انجام داده ایم در این پنجره نمایش داده می شود.
پارتیشن بندی (Partition) در Sql Server
  1. در این مرحله اسکریپ کارهایی که می خواهیم انجام دهیم را خواهیم دید. با اجرای این اسکریپت جدول شما پارتیشن خواهد شد.
    مطابق کوئری زیر از Rang Left استفاده شده است.  به کدهای زیر دقت کنید.
پارتیشن بندی (Partition) در Sql Server
پارتیشن بندی (Partition) در Sql Server

ایندکس گذاری (Index) روی جداول در Sql Server

مزیت ایندکس:

افزایش قابل توجه سرعت کوئری های select.

معایب ایندکس:

کاهش سرعت کوئری های insert و update.

اشغال بیشتر فضای حافظه.

انواع ایندکس:

  1. ایندکس index (برای افزایش سرعت در جستجوی مقدار)
  2. ایندکس unique (علاوه بر افزایش سرعت در جستجوی مقدار، یکتا بودن مقدار ستون رو هم چک می کند)
  3. ایندکس full-text (برای افزایش سرعت در جستجوی مقدارهایی از جنس متون نسبتا طولانی)
  4. ایندکس spatial (برای افزایش سرعت در جستجوی مقدارهایی از جنس موقعیت های مکانی)
  5. ایندکس primary (کلید اصلی جدول هست و علاوه بر جلوگیری از ورود مقدار تکراری از ورود null ها هم جلوگیری میکند)

نحوه ایجاد ایندکس روی جدول در Sql Server

جدول مورد نظر را که میخواهید روی آن ایندکس ایجاد کنید را انتخاب کنید و آن را باز کنید تا پوشه Indexes را مشاهده کنید.

ایندکس گذاری (Index) روی جداول در Sql Server

روی Indexes کلیک راست کنید و گزینه New Index و Non Clustred Index را انتخاب کنید.

ایندکس گذاری (Index) روی جداول در Sql Server

فرم New Index باز می شود. در این فرم باید مشخصات ایندکسی را که میخواهیم ایجاد کنیم تعیین کنیم. به تصویر زیر دقت کنید

ایندکس گذاری (Index) روی جداول در Sql Server

در قسمت شماره 1 نام جدولی که قرار است بر روی یک یا چند فیلد آن ایندکس گذاری شود نمایش داده می شود.

در قسمت شماره 2 باید نام ایندکس را مشخص کنید. دقت کنید که ایندکس آبجکت ها یا اشیای دیتابیس محسوب می شوند و باید نام منحصر بفرد داشته باشند. یعنی شما نمی توانید در یک دیتابیس 2 ایندکس هم نام داشته باشید.

در قسمت شماره 3 نوع ایندکس مشخص می شود که non clustred می باشد.

و در قسمت شماره 4 هم ستون یا ستون هایی که قرار است درگیر این ایندکس باشند مشخص می شود.

خب روی دکمه Add کلیک کنید تا یک ایندکس جدید ایجاد کنیم. فرم Select Column باز می شود. در این فرم باید ستون یا ستون هایی را که می خواهید روی آنها ایندکس ایجاد شود را انتخاب کنید.

ایندکس گذاری (Index) روی جداول در Sql Server

روی دکمه Ok کلیک کنید تا به فرم قبل برگردید. حالا ستون هایی که قرار است ایندکس گذاری شود مشخص شده است.

ایندکس گذاری (Index) روی جداول در Sql Server

روی دکمه Ok کلیک کنید تا ایندکس شما ایجاد شود. حالا ایندکس شما باید در لیست ایندکس های جدول شما نمایش داده شود.

ایندکس گذاری (Index) روی جداول در Sql Server

خب به این ترتیب شما موفق به ایجاد یک ایندکس non Clustered بر روی جدول خود شده اید.

معیارهای ایندکس گذاری بر روی جداول در Sql Server :

خب سوال اساسی اینجاست که چگونه تشخیص دهیم که یک جدول نیاز به ایندکس گذاری دارد یا خیر! و اگر نیاز به ایندکس گذاری دارد کدام ستون ها را برای ایندکس گذاری انتخاب کنیم. جهت ایجاد ایندکس بر روی جداول و همچنین انتخاب ستونهای ایندکس به نکات زیر توجه کنید.

معمولا بر روی جداولی باید ایندکس گذاری انجام شود که تعداد ستون های آنها زیاد می باشد.

معمولا بر روی جداولی باید ایندکس گذاری انجام شود که تعداد رکورهای خیلی زیادی دارد.

سعی کنید بر روی جداولی ایندکس گذاری کنید که تراکنش های زیادی در آن جدول انجام می شود. به عنوان مثال ممکن است جدولی تعداد ستون و ردیف زیادی هم داشته باشد ولی در روز یکی دو بار بیشتر از آن جدول استفاده نشود.

برای ایندکس گذاری فیلدهایی را انتخاب کنید که بیشتر مورد جستجو قرار می گیرند.

تا حد ممکن سعی کنید ایندکس گذاری بر روی یک فیلد انجام شود. مثلا از انتخاب چند فیلد در یک جدول ترجیحا خود داری نمایید.

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

انواع ایندکس در Sql Server :

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

Clustred Index :  این ایندکس به صورت اتوماتیک بر روی همه جداول و بر اساس کلید اصلی ایجاد می شود.

Non Clustred Index : این ایندکس ها را طراح دیتابیس با توجه به نیاز می تواند ایجاد کند.

ساخت API در Asp.net core با GraphQl و Sqlite

  1. ایجاد پروژه جدید : ابتدا یک پروژه جدید ASP.NET Core Web API ایجاد کنید:
ساخت API در Asp.net core با GraphQl و Sqlite

پس از ایجاد

ساخت API در Asp.net core با GraphQl و Sqlite

یک پوشه جدید با نام Data ایجاد میکنیم که می خواهیم تمام کدهای مربوط به پایگاه داده خود را در آن قرار دهیم.

  • ایجاد مدل Speaker.cs در پوشه Data :

با استفاده از کد زیر یک فایل جدید Speaker.cs در دایرکتوری Data اضافه کنید :

  • پیکر بندی Sqlite :
  • پکیج های زیر از NuGet دریافت و  نصب میکنیم :
  • یک Entity Framework DbContext جدید با نام کلاس ApplicationDbContext.cs در پوشه Data ایجاد میکنیم:
  • پیکر بندی Startup.cs :

در Startup.cs خط کد زیر را به سرویس ها  اضافه میکنیم

  • پیکر بندی EF Migrations :

در  Visual Studio، Tools -> NuGet Package Manager -> Package Manager Console  را انتخاب کنید.

دستورات زیر را جهت Migration و آپدیت دیتابیس در Package Manager Console اجرا کنید

  • اضافه کردن GraphQL :
  • پکیج زیر را از NuGet دریافت نمایید:
  • در مرحله بعد ما نوع ریشه پرس و جو خود ( Query.cs) را در پوشه Data ایجاد می کنیم و resolver  اضافه می کنیم که همه speakers ما را واکشی کند.
  • قبل از اینکه بتوانیم کاری با نوع ریشه پرس و جو خود انجام دهیم، باید GraphQL را راه اندازی کنیم و نوع ریشه پرس و جو خود را ثبت کنیم. کد زیر را  در متد Startup.cs اضافه کنید.
  • در مرحله بعد باید میان افزار GraphQL خود را پیکربندی کنیم تا سرور بداند که چگونه درخواست های GraphQL را اجرا کند. برای این کار  app.UseEndpoints…کد زیر را در  Startup.cs اضافه میکنیم.

حال پروژه را اجرا نمایید و می بایست بعد از ورود به آدرس زیر پروژه  ذیل نمایش داده شود.

ساخت API در Asp.net core با GraphQl و Sqlite

برای بررسی نوع برگشتی فیلد speakers ، روی schema explorer کلیک کنید و روی فیلد  speakers کلیک کنید .
توجه: ممکن است مجبور شوید طرح را دوباره بارگیری کنید، می توانید این کار را با کلیک کردن روی دکمه refresh در گوشه سمت راست بالا انجام دهید.

ساخت API در Asp.net core با GraphQl و Sqlite
  • اضافه کردن Mutation  :

بنابراین، تا کنون نوع ریشه Query را به طرح خود اضافه کرده‌ایم که به ما امکان می‌دهد از speakers پرس و جو کنیم. با این حال، در این مرحله، هیچ راهی برای افزودن یا تغییر داده وجود ندارد. در این بخش قصد داریم تا نوع root Mutation را اضافه کنیم تا speakers جدیدی به پایگاه داده خود اضافه کنیم.

برای Mutation  از الگوی Relay Mutation  استفاده می‌کنیم که معمولاً در GraphQL استفاده می‌شود.

یک جهش از سه جزء تشکیل شده است، Input ، Payload و خود Mutation  

در این مورد ما می خواهیم یک Mutation به نام ایجاد کنیم addSpeaker، طبق قرارداد، جهش ها به عنوان فعل نامگذاری می شوند، ورودی های آنها نامی است که در انتها “Input” ضمیمه شده است، و آنها یک شی است که نام آن با “Payload” اضافه شده است.

بنابراین، برای  addSpeakerجهش خود، دو نوع ایجاد می کنیم AddSpeakerInput و AddSpeakerPayload :

  1.  AddSpeakerInput.csبا کد زیر یک فایل به پروژه خود اضافه کنید :

ورودی و خروجی (بارگذاری بار) هر دو حاوی یک شناسه جهش مشتری هستند که برای تطبیق درخواست ها و پاسخ ها در برخی از چارچوب های مشتری استفاده می شود.

  • سپس ما را اضافه می کنیم  AddSpeakerPayloadکه خروجی جهش GraphQL ما را با افزودن کد زیر نشان می دهد:
  • حالا بیایید نوع جهش واقعی را با addSpeakerجهش خود در آن اضافه کنیم.
  • حال در program.cs باید Mutation نوع جدید را به طرح خود اضافه کنید:
  • تست خروجی  :
  • اکنون باید یک نوع Query به نام Speacker و یک Mutation به نام addSpeaker وجود داشته باشد.
ساخت API در Asp.net core با GraphQl و Sqlite
  • سپس با نوشتن یک جهش GraphQL یک Speaker اضافه کنید.
ساخت API در Asp.net core با GraphQl و Sqlite
  • نام همه Speackers پایگاه داده را جویا شوید.
ساخت API در Asp.net core با GraphQl و Sqlite
ساخت API در Asp.net core با GraphQl و Sqlite
  • سورس کد پروژه در آدرس ذیل قابل دریافت می باشد  :

https://github.com/miladshafiyan/ASPNetCoreGraphQL

انتشار پروژه های ASP.net Core با استفاده از Docker

برای اینکه بتوانیم در هر سیستم عاملی پروژه های ASP.net Core با استفاده از Docker انتشار دهیم می بایست مراحل زیر را دنبال نماییم.

برای شروع باید ابتدا یک پروژه ی ASP.net Core ایجاد میکنیم.

پس از نصب SDK نرم افزار Visual Studio را باز کنید. با صفحه شروع روبرو می شوید برروی گزینه ی Create a new project که در تصویر زیر مشخص است کلیک کنید:

انتشار پروژه های ASP.net Core با استفاده از Docker

سپس در صفحه بعد گزینه ی ASP.net Core Web Application را همانند تصویر زیر جستجو و انتخاب میکنیم.

پس از آن در صفحه بعد مشخصات کلی پروژه خود یعنی نام، محل ذخیره سازی را وارد کرده و روی دکمه ی Create کلیک کنید.

انتشار پروژه های ASP.net Core با استفاده از Docker

در صفحه بعد، در بالای صفحه نسخه ی ASP.NET Core مورد نظر خود را انتخاب و از لیست نشان داده شده همانند تصویر زیر گزینه ی API  را انتخاب کنید.

توجه نمایید که دو گزینه ی Configure for HTTPS و Enable Docker Support غیر فعال باشد زیرا نمی خواهیم از این قابلیت ها استفاده کنیم. سپس روی دکمه ی Create کلیک کنید.

انتشار پروژه های ASP.net Core با استفاده از Docker

پس از انجام مراحل فوق، فایل های اولیه ی پروژه ی ASP.net Core شما ایجاد می شود. ساختار فایل ها و پوشه ها را می توانید در بخش Solution Explorer  همانند تصویر زیر مشاهده کنید.

انتشار پروژه های ASP.net Core با استفاده از Docker

به صورت مختصر فایل ها و پوشه های مهم عبارتند از:

Program.cs :  داخل این فایل، تابع اصلی یعنی main برنامه قرار دارد و اولین تابعی است که پس از شروع پروژه، اجرا می شود. در این فایل عموما تنظیماتی که به ندرت تغییر می کنند و مربوط به کلیات پروژه هستند نظیر تنظیمات  Logها قرار می گیرد.

 Startup.cs :  داخل این فایل کلاس Startup قرار دارد. ما با این فایل در فرآیند توسعه پروژه های ASP.net Core خود خیلی کار خواهیم داشت. پروژه های ASP.net Core مبتنی بر سرویس و میان افزار هستند که همه ی آن ها در کلاس Startup تعریف می شوند.

Controllers :  درون این پوشه کنترلرهای برنامه ما قرار دارد. همانطور که اطلاع دارید ASP.net Core از معماری MVC برای توسعه برنامه ها استفاده می کند.

نصب Docker روی سیستم عامل

حال Docker را روی سیستم عامل خود نصب کنید.

ایجاد  Dockerfile

خوب حالا نیاز به یک فایل با عنوان Dockerfile بدون هیچ پسوند و پیشوندی دارید. این فایل را در پوشه پروژه ی خود ایجاد کنید. Dockerfile  به منظور ایجاد Imageهای docker مورد استفاده قرار می گیرد و حاوی دستورالعمل ها و مراحل ایجاد Image دلخواه است.

Imageهای docker عملا نسخه های سبک شده ای از سیستم عامل های مختلف به همراه ملزمات دیگری هستند که برای اهداف خاص استفاده می شوند. برای مثال یک image داکر برای راه اندازی دیتابیس mysql وجود دارد که حاوی یک نسخه ی سبک شده از سیستم عامل لینوکس به همراه دیتابیس mysql که روی آن نصب شده است می باشد.

ما در این آموزش فرض می کنیم نام پروژه ی شما (همانند source code ارائه شده برای این آموزش DockerASPnetCore است. اکنون دستورالعمل های زیر را در Dockerfile که ایجاد کردید قرار دهید:

در این دستورالعمل ها ما از Image پایه ی mcr.microsoft.com/dotnet/core/sdk:2.2-stretch استفاده کردیم که مربوط بهASP.net Core 2.2  است. اگر از نسخه ی دیگری از ASP.net Core استفاده می کنید لطفا Image مناسب را  انتخاب و در فایل Dockerfile  خود جایگیزین کنید. حجم این Image تقریبا 1.7GB  است پس لطفا برای pull شدن آن کمی صبر کنید.

در قدم بعد با استفاده از دستور

یک پوشه با نام app درون Image مورد نظر ایجاد می شود. سپس با دستور

 پوشه ی جاری را به app تغییر می دهد. آنگاه فایل DockerASPnetCore.csproj پروژه ی ما را با دستور بعدی در Image کپی می کند. پس از آن با اجرای دستور

ملزومات لازم برای پروژه ما از Nuget گرفته می شود.

در قدم بعد نیز کل فایل های پروژه ما درون پوشه ی app در ایمیج کپی می شود و پس از آن با اجرای دستور

پروژه ما build شده و در پوشه ی out منتشر می شود.

سپس با اجرای دستور

 امکان ارتباط پورت 5000 مربوط به Image با بیرون وجود خواهد داشت. و در نهایت با اجرای فایل out/DockerASPnetCore.dll توسط فرمان dotnet که به محض ایجاد یک container از روی image اجرا می شود پروژه ی ما را اجرا می کند.

ایجاد  Docker Image

در قدم بعد باید از روی Dockerfile یک Image داکر ایجاد کنیم. بدین منظور دستور زیر را در خط فرمان در حالی که در پوشه ی پروژه ی خود هستید اجرا کنید:

به جای aspnet-app:2.2 می توانید از هرنام و tag دیگری برای نام image خود استفاده کنید. پس از Image مورد نظر توسط داکر ایجاد شده و تمامی فرامین شما در Dockerfile به ترتیب اجرا می شود. اکنون می توانید با اجرای فرمان docker images در خط فرمان لیست  imageهای خود را مشاهده کنید.

ایجاد Container و اجرای پروژه

اکنون که Image شما ایجاد شد، می توانید با اجرای دستور زیر در خط فرمان یک Container از روی آن ایجاد کرده و پروژه ی خود را اجرا کنید:

در صورتی که پروژه ی شما به صورت پیش فرض روی پورتی به جز 80 در حال اجراست لطفا مقدار 80 را به شماره پورت پروژه ی خود تغییر دهید. همچنین به جای app می توانید از هر نام دیگری برای container خود استفاده کنید.

نکته:  در برخی موارد نیاز است برای اجرای برخی از دستورات docker خط فرمان خود را به صورت Run as adminstrator باز کنید کاربران linux نیاز به استفاده از دستور sudo دارند

برای مشاهده ی log پروژه ی خود می توانید دستور docker logs app را در خط فرمان اجرا کنید. اکنون پروژه در حال اجراست. با مراجعه به آدرسhttp://localhost:5000/api/Values  از صحت اجرای پروژه اطمینان حاصل کنید.

C#

C# چیست؟

C# یک زبان برنامه‌نویسی مدرن، شیءگرا و چندمنظوره است که توسط مایکروسافت به عنوان بخشی از .NET Framework توسعه داده شده است. این زبان تحت هدایت آندرس هجلزبرگ (Anders Hejlsberg) ایجاد شد و اولین بار در سال 2000 معرفی شد. هدف از ایجاد C# ارائه زبانی قدرتمند، انعطاف‌پذیر و ایمن برای توسعه‌دهندگان بود که بتوانند برنامه‌های کاربردی مدرن را به راحتی و با کارایی بالا توسعه دهند.

فلسفه به وجود آمدن C#

C# با اهداف و فلسفه‌های خاصی طراحی و توسعه یافت:

  1. سادگی و راحتی استفاده: یکی از اهداف اصلی C# ساده‌سازی فرآیند توسعه نرم‌افزار بود. این زبان سعی کرده است که از پیچیدگی‌های موجود در برخی زبان‌های دیگر کاسته و ویژگی‌هایی ارائه دهد که توسعه‌دهندگان را در نوشتن کدهای خوانا و نگهداری آسان‌تر یاری کند.
  2. ایمنی و امنیت: C# به شدت بر ایمنی نوع (type safety) تاکید دارد تا از خطاهای زمان اجرا و آسیب‌پذیری‌های امنیتی جلوگیری کند. ویژگی‌هایی مانند مدیریت خودکار حافظه (garbage collection) و بررسی‌های زمان کامپایل (compile-time checks) این اهداف را محقق می‌کنند.
  3. کارایی و عملکرد: C# طراحی شده است تا بهینه‌سازی‌های مختلفی را فراهم کند که باعث افزایش عملکرد برنامه‌ها می‌شوند. این زبان به گونه‌ای طراحی شده که توسعه‌دهندگان بتوانند از تمامی امکانات سخت‌افزاری موجود بهره‌برداری کنند.
  4. مدرنیته و انعطاف‌پذیری: با توجه به تغییرات سریع تکنولوژی و نیازهای توسعه‌دهندگان، C# به گونه‌ای طراحی شده که به راحتی قابلیت ارتقاء و افزودن ویژگی‌های جدید را داشته باشد.
  5. پشتیبانی از توسعه تحت پلتفرم‌های مختلف: با معرفی .NET Core و سپس .NET 5 و نسخه‌های بعدی، C# قابلیت اجرای برنامه‌ها روی سیستم‌عامل‌های مختلف مانند ویندوز، لینوکس و macOS را دارا شده است.

آخرین نسخه حال حاضر C#

تا تاریخ دانش من (جولای 2023)، آخرین نسخه رسمی C#، نسخه 11 است. البته، برای اطلاع از آخرین نسخه دقیق، بهتر است به منابع رسمی مایکروسافت مراجعه کنید.

ویژگی‌های کلیدی آخرین نسخه C#

ویژگی‌های زیر نمونه‌هایی از قابلیت‌های جدیدی هستند که در نسخه‌های اخیر C# اضافه شده‌اند:

  1. Records: نوع جدیدی برای تعریف کلاس‌های داده‌محور (immutable data classes).
  1. Top-level statements: نوشتن برنامه‌های ساده‌تر بدون نیاز به تعریف صریح کلاس و متد Main.
  1. Pattern matching enhancements: بهبود قابلیت‌های تطابق الگو، شامل switch expressions و property patterns.
  1. Nullable reference types: قابلیت جدید برای جلوگیری از null reference exceptions با استفاده از نشانه‌گذاری نال‌پذیر.
  1. Async streams: پشتیبانی از بازگشت داده‌ها به صورت غیرهمزمان با استفاده از IAsyncEnumerable<T>.
  1. Init-only properties: امکان تعریف ویژگی‌های فقط برای مقداردهی اولیه.
  1. Record structs: نوعی struct که ویژگی‌های مشابهی با records دارند.
  1. Enhanced interpolated strings: بهبود در رشته‌های interpolated برای انجام عملیات‌های پیچیده‌تر.

Entity Framework (EF)

فرق Tracking و AsNoTracking در Entity Framework (EF) :

در Entity Framework (EF)، دو روش اصلی برای بازیابی داده‌ها از پایگاه داده وجود دارد: Tracking و AsNoTracking. این دو روش تاثیر مهمی بر عملکرد و رفتار پرس و جوها دارند. تفاوت‌های کلیدی بین این دو روش عبارتند از:

Tracking (ردیابی)

  • عملکرد: وقتی از ردیابی استفاده می‌کنید، Entity Framework موجودیت‌های بازیابی شده از پایگاه داده را در ChangeTracker ردیابی می‌کند. این به این معنی است که هر تغییری که در این موجودیت‌ها انجام شود، توسط EF شناسایی شده و هنگام ذخیره تغییرات (SaveChanges) به طور خودکار به پایگاه داده اعمال می‌شود.
  • مزایا:
    • قابلیت پیگیری تغییرات: اگر می‌خواهید تغییراتی که روی موجودیت‌ها انجام می‌شود را ردیابی و در نهایت به پایگاه داده اعمال کنید، ردیابی مناسب است.
    • همگام‌سازی خودکار: EF به طور خودکار تغییرات را به پایگاه داده اعمال می‌کند.
  • معایب:
    • عملکرد پایین‌تر: ردیابی موجودیت‌ها نیازمند حافظه و پردازش بیشتری است که می‌تواند در پرس و جوهای بزرگ یا پیچیده منجر به افت عملکرد شود.

AsNoTracking (بدون ردیابی)

  • عملکرد: وقتی از AsNoTracking استفاده می‌کنید، EF موجودیت‌های بازیابی شده از پایگاه داده را در ChangeTracker ردیابی نمی‌کند. این باعث می‌شود که پرس و جوها سریع‌تر اجرا شوند و حافظه کمتری مصرف کنند.
  • مزایا:
    • عملکرد بهتر: چون EF موجودیت‌ها را ردیابی نمی‌کند، پرس و جوها سریع‌تر اجرا می‌شوند و منابع کمتری مصرف می‌شود.
    • مناسب برای سناریوهای فقط خواندنی: اگر تنها به خواندن داده‌ها نیاز دارید و نمی‌خواهید آن‌ها را به روزرسانی کنید، AsNoTracking انتخاب بهتری است.
  • معایب:
    • عدم پیگیری تغییرات: تغییراتی که روی موجودیت‌ها انجام می‌شود توسط EF شناسایی نمی‌شود و باید به صورت دستی مدیریت شوند.
    • نیاز به مدیریت دستی: اگر بعداً تصمیم به اعمال تغییرات داشتید، باید موجودیت‌ها را مجدداً به ChangeTracker اضافه کنید.

مثال

در اینجا مثالی از استفاده از هر دو روش آورده شده است:

Tracking

AsNoTracking

نکات نهایی

  • استفاده از AsNoTracking برای سناریوهای فقط خواندنی (read-only) بسیار مناسب است زیرا عملکرد را بهبود می‌بخشد.
  • در صورت نیاز به ردیابی و اعمال تغییرات به پایگاه داده، باید از ردیابی استفاده کنید.
  • Entity Framework Core به طور پیش‌فرض از ردیابی Tracking استفاده می‌کند مگر اینکه به طور صریح از AsNoTracking استفاده کنید.

تفاوت بین IQueryable و IEnumerable :

در اصل متد IQueryable از متد IEnumerable ارث بری میکنه و طبیعتا تمام ویژگی های آن را دارد اما در اصل IQueryable سمت SQL ریکوئستی را ارسال نمیکند و زمانی که دستور ()ToList را بهش میدهیم میره و اطلاعات را برای ما از سمت SQL فراخوانی میکنه به گ.نه ای که میتوان بارها با دستور where  کوئری را مفصل تر نمود و در نهایت بعد از زدن ()ToList میره و اطلاعات را از SQL میاره ولی IEnumerable پس از هر بار where  زدن می بایست دستور ()ToList را نوشت و هر بار دیتا را برای ما از سمت sql میاره

توضیحات تکمیلی:

متد زیر را که یکی از اشتباهات رایج حین استفاده از LINQ خصوصا جهت Binding اطلاعات است، در نظر بگیرید:


این متد در حقیقت هیچ چیزی را Get نمی‌کند! نام اصلی آن GetQueryableCustomers و یا GetQueryObjectForCustomers است.
IQueryable قلب LINQ است و تنها بیانگر یک عبارت (expression) از رکوردهایی می‌باشد که مد نظر شما است و نه بیشتر.

برای مثال زمانیکه یک IQueryable را همانند مثال فوق فیلتر می‌کنید نیز هنوز چیزی از بانک اطلاعاتی یا منبع داده‌ای دریافت نشده است. هنوز هیچ اتفاقی رخ نداده است و هنوز رفت و برگشتی به منبع داده‌ای صورت نگرفته است.
به آن باید به شکل یک expression builder نگاه کرد و نه لیستی از اشیاء فیلتر شده‌ی ما. به این مفهوم، deferred execution (اجرای به تاخیر افتاده) نیز گفته می‌شود (باید دقت داشت که IQueryable هم یک نوع IEnumerable است به علاوه expression trees که مهم‌ترین وجه تمایز آن نیز می‌باشد.
برای مثال در عبارت زیر تنها در زمانیکه متد ToList فراخوانی می‌شود، کل عبارت LINQ ساخته شده، به عبارت SQL متناظر با آن ترجمه شده، اطلاعات از دیتابیس اخذ گردیده و حاصل به صورت یک لیست بازگشت داده می‌شود:


در مورد IEnumerable ها چطور؟

دو سطر فوق به این معنا است:
لطفا ابتدا به بانک اطلاعاتی رجوع کن و تمام رکوردهای محصولات موجود را بازگشت بده. سپس بر روی این حجم بالای اطلاعات، محصولاتی را که قیمت بالای 25 دارند، فیلتر کن.

اگر همین دو سطر را با IQueryable بازنویسی کنیم چطور؟

در سطر اول تنها یک عبارت LINQ ساخته شده است و بس. در سطر دوم نیز به همین صورت. در طی این دو سطر حتی یک رفت و برگشت به بانک اطلاعاتی صورت نخواهد گرفت. در ادامه اگر این اطلاعات به نحوی Select شوند (یا ToList فراخوانی شود، یا در طی یک حلقه برای مثال Iteration ایی روی این حاصل صورت گیرد یا موارد مشابه دیگر)، آنگاه کوئری SQL متناظر با عبارت LINQ فوق ساخته شده و بر روی بانک اطلاعاتی اجرا خواهد شد.
بدیهی است این روش منابع کمتری را نسبت به حالتی که تمام اطلاعات ابتدا دریافت شده و سپس فیلتر می‌شوند، مصرف می‌کند (حالت بازگشت تمام اطلاعات ممکن است شامل 20000 رکورد باشد، اما حالت دوم شاید فقط 5 رکورد را بازگشت دهد).

سوال: پس IQueryable بسیار عالی است و از این پس کلا از IEnumerable ها دیگر نباید استفاده کرد؟
خیر! توصیه اکید طراحان این است که لطفا تا حد امکان متدهایی که IQueryable بازگشت می‌دهند ایجاد نکنید! IQueryable یعنی اینکه این نقطه‌ی آغازین کوئری در اختیار شما، بعد برو هر کاری که دوست داشتی با آن در طی لایه‌های مختلف انجام بده و هر زمانیکه دوست داشتی از آن یک خروجی تهیه کن. خروجی IQueryable به معنای مشخص نبودن زمان اجرای نهایی کوئری و همچنین مبهم بودن نحوه‌ی استفاده از آن است. به همین جهت متدهایی را طراحی کنید که IEnumerable بازگشت می‌دهند اما در بدنه‌ی آن‌ها به نحو صحیح و مطلوبی از IQueryable استفاده شده است. به این صورت حد و مرز یک متد کاملا مشخص می‌شود. متدی که واقعا همان فیلتر کردن محصولات را انجام می‌دهد، همان 5 رکورد را بازگشت خواهد داد؛ اما با استفاده از یک لیست یا یک IEnumerable و نه یک IQueryable که پس از فراخوانی متد نیز به هر نحو دلخواهی قابل تغییر است.

Left Join در Entity Framework با استفاده از LINQ :

برای انجام یک عملیات Left Join در Entity Framework (EF)، می‌توانید از روش‌های مختلفی استفاده کنید. یکی از رایج‌ترین روش‌ها استفاده از LINQ (Language Integrated Query) است. در ادامه، مثالی از نحوه اجرای یک Left Join در EF با استفاده از LINQ آمده است.

فرض کنید دو جدول Customers و Orders داریم و می‌خواهیم یک Left Join بین این دو جدول انجام دهیم تا تمام مشتریان و سفارش‌های آنها (در صورت وجود) را به دست آوریم.

تعریف کلاس‌های مدل





اجرای Left Join با استفاده از LINQ

در این مثال، یک Left Join بین Customers و Orders انجام می‌دهیم تا تمامی مشتریان و سفارش‌های آنها (در صورت وجود) را بازیابی کنیم.





توضیح کد

  1. تعریف کوئری:
    • از عبارت from و join برای تعریف جوین بین Customers و Orders استفاده می‌کنیم.
    • از into customerOrders برای تعریف گروه جوین استفاده می‌کنیم.
    • از from order in customerOrders.DefaultIfEmpty() برای انجام Left Join استفاده می‌کنیم. DefaultIfEmpty() اطمینان حاصل می‌کند که اگر هیچ سفارشی برای یک مشتری وجود نداشته باشد، مقدار order برابر با null خواهد بود.
  2. انتخاب داده‌ها:
    • در قسمت select، اطلاعات مشتری و سفارش (در صورت وجود) را انتخاب می‌کنیم.
    • اگر سفارشی وجود نداشته باشد، مقادیر مربوط به سفارش برابر با null خواهند بود.
  3. اجرا و نمایش نتیجه:
    • کوئری با استفاده از ToList() اجرا می‌شود.
    • نتیجه کوئری چاپ می‌شود.

این روش ساده‌ترین و رایج‌ترین روش برای انجام Left Join در Entity Framework با استفاده از LINQ است.

سطوح دسترسی (Access Modifiers) در C#

Public : در هرجایی از کلاس

Private : فقط داخل کلاس

Protected : تنها در آن کلاس و زیرکلاس هایش

Internal : داخل assemly کلاس

Protected Intenal : داخل آن کلاس، زیرکلاس هایش و assembly

Access Modifiers

Access Modifiers سطح مشخصی از مجوز برای دسترسی به خصوصیات و متدها می باشد. با اعلام تغییر دسترسی یک متغیر تعریف می کنیم یا حتی می توانیم از assembly به داخل کلاس دسترسی داشت.

Public

با استفاده از public یک رویداد یا متغیر می تواند از خارج از کلاس قابل دستیابی باشد. جایی که متعلق به آن است. و همینطور خارج از assembly

Private

استفاده از متدها و متغیرها را تنها در کلاس خودش محدود می کند و خارج از کلاس نمی تواند استفاده شود. همانطور که یک سازنده private از یک کلاس را اعلان می کنید. که نمی تواند خارج از کلاس قابل استفاده باشد. و نمی توان از آن کلاس یک شی ایجاد کنید.

مثالی از کلیدواژه Private

مثالی از private Constructor

Protected

protected اجازه دسترسی متغیرها و متدها از کلاس و زیرکلاس را می دهد. بدین معنا که متدها می توانند از داخل کلاس و کلاسی که از آن ارث بری کرده است قابل دسترسی باشند.

Internal

internal در #C معرفی شده است. در جاوا ما این سطح دسترسی را نداریم. این دستیابی بعد از Protected می باشد. protected اجازه دستیابی از کلاس و زیرکلاس را می دهد.  assembly را به آن اضافه می کند. بدین معنا که متغیرها ومتدها می توانند درون assemly جایی که کلاس به آن تعلق دارد قابل دسترسی باشند. assembly و NameSpace اندکی متفاوت می باشند. یک assembly می تواند بیش از یک namespace را نگهداری کند. assemblyها در واقع Dllهای یک پروژه می باشند.

Protected Internal

اجازه دسترسی از کلاس و زیرکلاس را می دهد. هچنین اجازه دسترسی از همان assembly را می دهد. بدین معنا که در protected اگر کلاس ارث بری کرده باشد، super class و متد یا متغیر protected می باشند، سپس دسترسی assembly مهم نیست. اما در Internal اگر کلاس ارث بری کرده باشد assembly مهم می باشد. در زیر می بینید که چرا از Protected Internal استفاده می کنیم.

متدها و اعضای کلاس‌ها در C#

معرفی مفاهیم virtual, override, abstract‌ و sealed در #C :

همانطور که مستحضر هستید کلمه‌ی Polymorphism به معنای چندریختی است. در برنامه‌نویسی شیءگرا پلی مورفیسم اغلب به عنوان یک تغییردهنده رفتار یا یک واسط چند متدی مطرح می‌شود.

در زبان برنامه‌نویسی #C پلی مورفیسم به سه شکل ممکن پیاده‌سازی می‌شود:

1- استفاده از متدهای virtual و override کردن آنها در کلاس فرزند

2- بهره‌گیری از متدهای abstract در کلاس والد

3- بهره‌گیری از قابلیت واسط‌ها یا Interfaceها ( واسط‌ها در فصول بعدی به تفصیل توضیح داده خواهند شد)

متدهای virtual

فرض کنید یک کلاس والد به نام Shape دارید که در آن متدی به نام Draw تعریف شده است. متد Draw وظیفه‌ی ترسیم یک شیء یا شکل را به عهده دارد. این متد در تمام کلاس‌هایی که از این کلاس مشتق می‌شوند قابل استفاده است. بنابراین کلاس Shape را به صورت زیر می‌نویسم:

حال باید کلاس‌های فرزند مرتبط با این کلاس را تعریف کنیم بنابراین سه کلاس به نام‌های Triangle و Rectangle و Circle را تعریف می‌کنیم که هر سه از کلاس والد یعنی Shape مشتق شده اند:

هر سه کلاسی که در فوق تعریف کردیم می‌توانند از متد Draw استفاده کنند زیرا این متد در کلاس اصلی والد تعریف شده است. حال اگر شیءای بسازیم آنگاه:

در نهایت خروجی دستورات به صورت زیر است:

اما این خروجی مورد پسند نیست و باید برای هر کلاس یک شکل کشیده شود در نهایت برای رفع این مشکل متد موجود در کلاس والد را به صورت virtual تعریف کرده و آن را درون کلاس فرزند override می‌کنیم. بنابراین تغییراتی در کلاس والد داده و متد Draw را به صورت زیر تعریف می‌کنیم:

حال همین تغییرات را درون کلاس‌های فرزند انجام می‌دهیم:

حال خروجی دستورات فوق به صورت زیر اصلاح می‌شوند:

همچنین اگر از کلمه‌ی کلیدی base درون متد کلاس فرزند استفاده کنیم محتوا و متد کلاس پایه نمایش داده خواهد شد:

استفاده از روش virtual و override‌ تنها به متدها ختم نمی‌شود بلکه می‌توان برای خصوصیات یا Property ها نیز این کار را انجام داد:

معرفی کلاس‌ها و متدهای abstract و sealed

هنگامیکه یک برنامه را می‌نویسیم و کلاس‌ها و اعضای آن را مشخص می‌کنیم باید برای استفاده از کلاس‌ها یک سری محدودیت بگذاریم. مثلا یک کلاس پایه داریم که این کلاس نباید توسط سایر کلاس ها مورد استفاده قرار بگیرد و تنها اعضای آن کلاس و کلاس هایی که از آن به ارث برده‌اند، توانایی دسترسی به متدها و اعضای آن را دارند یا مثلا کلاسی را ایجاد کرده‌ایم که با اعمال محدودیت‌هایی اجاره ایجاد کلاس فرزند از آن را نمی‌دهیم. برای اعمال همچین محدودیت‌هایی از کلاس‌ها یا متدهایی با فرم abstract یا sealed استفاده می‌شود.

کلاس‌ها و اعضاء abstract

به مثال قبلی باز می‌گردیم که یک کلاس والد به نام Shape داشتیم و از روی این کلاس سه فرزند ساخته بودیم:

اگر به مثال بالا مراجعه کنید متوجه می‌شوید که کلاس Shape عملا برای ما کاربردی ندارد. به عبارت دیگر در طول برنامه‌ی اصلی از آن استفاده نشده است. یعنی باید محدودیتی اعمال کنیم که از روی کلاس Shape شیء‌ای ایجاد نشود. برای اینکار کافیست کلاس Shape را از نوع abstract تعریف کنیم. بنابراین طی یک تعریف کلی برای abstract‌ داریم:

اگر کلاسی به صورت abstract ایجاد شود، در طول برنامه نمی‌توان از روی آن شیءای ساخت.

به مثال زیر توجه کنید:

حال اگر بخواهیم از روی کلاس Shape یک شیء ایجاد کنیم با خطای زیر مواجه می‌شویم:

یعنی نمی‌توان از روی کلاس‌هایی که به صورت abstract‌ تعریف شده‌اند شیءای ایجاد کرد.

اما کاربردهای بیشتری از کلاس abstract انتظار می‌رود. در کلاس‌های abstract‌ می‌توان به طور مشابه متدهایی را تعریف کرد که به صورت abstract‌ باشند. این متدها تنها شامل signature هستند یعنی بدنه‌ای نداشته و پس از تعریف آنها به علامت ; ختم می‌شوند.  درصورتیکه یک متد به صورت abstract تعریف شود بدین گونه است که حتما باید آن را جهت استفاده در طی برنامه یا کلاس دیگر override کنند. برای مثال یکبار دیگر کلاس Shape‌ را بازنویسی می‌کنیم:

همانطور که ملاحظه می‌کنید متدی به نام Draw‌ وجود دارد که بدنه‌ای ندارد. علت این امر تعریف این متد به صورت abstract است. حال اگر کلاس فرزندی از کلاس Draw به ارث ببرد باید همواره متد درون آن به صورت abstract قرار بگیرد. بنابراین داریم:

کلاس‌ها و اعضاء sealed

در بخش وراثت آموزش دادیم که همواره می‌توان یک زنجیره‌ی وراثت در اختیار داشت مثلا کلاس B از کلاس A و کلاس C از کلاس B مشتق شود. حال درنظر بگیرید که می‌خواهیم به نحوی این زنجیره‌ی وراثت را قطع کنیم. برای اینکار باید کلاس موردنظر را از نوع sealed تعریف کنیم. بنابراین در طی یک تعریف کلی داریم:

کلاس‌هایی که به صورت sealed مورد استفاده قرار می‌گیرند، باعث حذف زنجیره وراثت می‌شوند.

به مثال زیر توجه کنید:

در این کد کلاس B‌ از نوع sealed تعریف شده است و این موضوع بدین معناست که هیچ کلاس دیگری نمی‌تواند از کلاس B مشتق شود و یا متدها و ویژگی‌هایی را به ارث ببرد. به عنوان مثال اگر کد زیر را پیاده سازی کنیم:

آنگاه با خطای زیر روبه‌رو می‌شویم:

بدین معنی‌ست که شما نمی‌توانید از یک کلاس که به صورت sealed‌ تعریف شده است ویژگی یا متدی را به ارث ببرید.

یکی دیگر از کاربردهای عبارت sealed جلوگیری از override کردن یک متد است. به مثال زیر توجه کنید:

این مثال بدین صورت عمل می‌کند که اگر کلاسی از کلاس Rectangle مشتق شد، دیگر قابلیت override کردن متد Draw را نداشته باشد زیر در متد موجود در کلاس Rectangle، متد به صورت sealed تعریف شده است.

فرق Class و Struct در #C :

Struct در سی شارپ یک جایگزین سبک حجم برای کلاس ها هستند. پس زمانی که می خواهیم نسخه های زیادی از یک داده را مقداردهی کنیم از Struct در سی شارپ استفاده می کنیم. تو این قسمت در مورد مفهوم Struct حرف بزنیم و این که Struct چه فرقی با Class دارد، برای ایجاد Struct ابتدا یک Class اضافه می کنیم

بعد از ایجاد کلاس نام کلیدی کلاس را پاک می کنیم و می توانیم نامی که برای کلاسمان در نظر گرفتیم هم پاک کنیم و نام دلخواه خودمان بگذاریم.

و مثل کلاس می توانیم فیلد و تابع داشته باشیم:

داخل پنجره فرم شده و از Struct نمونه می سازیم:

سوال : اگر Struct تمام قابلیت های Class را دارد و هر دو مساوی هستند چرا هر دو را داخل زبان سی شارپ گذاشتند؟

این دو تا یک تفاوت هایی با هم دارند که الان با هم بررسی می کنیم:

در Struct لازم نیست برای ایجاد شی جدید از دستور new استفاده کنیم، می توانم مثل متغیر ساده int آن را تعریف کنم و بعد به آن مقدار بدهیم:

فیلدها را در struct نمی توان مقدار دهی کرد. پس اینجا را خوب دقت کنید تا به id مقدار ندهیم ، فضایی داخل حافظه به آن اختصاص نمی دهد.

الان یک کلاس هم می نویسیم بالای Struct تا با هم مقایسه کنیم:

خوب دقت کنید class از نوع Reference Type است اما Struct  از نوع Value Type است .

یعنی اگر من دو تا کلاس داشته باشم داخل یکی از آنها تغییر اعمال کنم داخل آن یکی کلاس هم اعمال می شود. با یک مثال بیشتر متوجه می شویم:

داخل پنجره فرم شده تا با نوشتن یک کد تفاوت class و Struct در سی شارپ را بفهمیم:

برنامه را اجرا می کنیم و روی button1 کلیک می کنیم انتظار می رود عدد 10 را نمایش دهد.

Class Struct

امّا مشاهده می کنیم که عدد 20 را نمایش می دهد چون class رفرنسی است یعنی می رود به آدرسش نگاه می کند و چون خاصیت ارث بری هم دارد مقدار خودش را به آدرسش می دهد .

این بار برنامه را اجرا می کنیم و روی button2 کلیک می کنیم تا کد Struct اجرا شود:

Class Struct

مشاهده می کنیدکه عدد 10 را نمایش می دهد چون Struct از نوع Value تایپ است یعنی در Struct هر کدام مقدار خودشان را نمایش می دهند.

تفاوت Struct و class

1- در class به محض ساخته شدن شی فضایی به آن اختصاص داده می شود ولی در Struct حتی با وجود ساخته شدن شی فضایی به آن اختصاص داده نمی شود تا زمانی که مقداری داخل آن فیلد قرار گیرد.

2- در Struct لازم نیست که برای شی از کلمه ی new استفاده شود.

3- class رفرنس تایپ است اما value , Struct تایپ است در نتیجه چون کلاس از فیلد رفرنس استفاده می کند بنابراین حافظه بیشتری اشغال می کند. ولی Struct چون از فیلد رفرنس استفاده نمی کند حافظه کمتری اشغال می کند .

4- کلاس می تواند وراثت داشته باشد امّا Struct نمی تواند وراثت داشته باشد .

5- Struct نمی تواند تابع مخرب داشته باشد.

شباهت Struct و class

هر دو می توانند تابع سازنده داشته باشند.( البته خود Struct دارای تابع سازنده پیش فرض می باشد ولی اگر برای آن یک تابع سازنده تعریف کردیم باید تمام فیلدها را در آن مقداردهی اولیه کنیم. و تابع سازنده در Struct باید حداقل یک پارامتر داشته باشد.)