چرا باید از ابزارهای 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
اگر SQL Server و MySQL بر روی سیستم شما نصب است، روشی ساده برای انتقال اطلاعات بین این دو وجود دارد که نیازی به دخالت هیچ نوع برنامهی جانبی نداشته و با امکانات موجود قابل مدیریت است.
ایجاد یک Linked server
برای اینکه SQL Server را به MySQL متصل کنیم میتوان بین این دو یک Linked server تعریف کرد و سپس دسترسی به بانکهای اطلاعاتی MySQL همانند یک بانک اطلاعاتی محلی SQL Server خواهد شد که شرح آن در ادامه ذکر میشود.
ابتدا نیاز است تا درایور ODBC مربوط به MySQL دریافت و نصب شود. آنرا میتوانید از اینجا دریافت کنید : (+)
سپس management studio را گشوده و در قسمت Server objects ، بر روی گزینهی Linked servers کلیک راست نمائید. از منوی ظاهر شده، گزینهی New linked server را انتخاب کنید:
در ادامه، باید تنظیمات زیر را در صفحهی باز شده وارد کرد:
در قسمت Linked server و Product name ، نام دلخواهی را وارد کنید.
Provider انتخابی باید از نوع Microsoft OLE DB Provider for ODBC Drivers باشد.
مهمترین تنظیم آن، قسمت Provider string است که باید به صورت زیر وارد شود (در غیر اینصورت کار نمیکند):
DRIVER={MySQL ODBC 5.1 Driver}; SERVER=localhost; DATABASE=testdb; USER=root; PASSWORD=mypass; OPTION=3;PORT=3306; CharSet=UTF8;
پس از انجام این تنظیمات بر روی دکمهی Ok کلیک کنید تا Linked server ساخته شود:
اگر لیست بانکهای اطلاعاتی را مشاهده نمودید، یعنی اتصال به درستی برقرار شده است.
تنظیمات ثانویه:
تا اینجا اس کیوال سرور به MySQL متصل شده است، اما برای استفاده بهینه از امکانات موجود نیاز است تا یک سری تغییرات دیگر را هم اعمال کرد.
تنظیم MSDASQL Provider :
در همان قسمت Linked provider ، ذیل قسمت Providers ، گزینهی MSDASQL را انتخاب کرده و بر روی آن کلیک راست نمائید. سپس صفحهی خواص آنرا انتخاب کنید تا بتوان تنظیمات زیر را به آن اعمال کرد. این پروایدر جهت اتصال به MySQL مورد استفاده قرار میگیرد.
فعال سازی RPC :
برای اینکه بتوان از طریق SQL Server رکوردی را در یکی از جداول بانکهای اطلاعاتی MySQL متصل شده ثبت نمود، میتوان از دستور زیر استفاده کرد:
EXECUTE('insert into testdb.testtable(f1,f1) values(1,''data'')') at mysql
اینجا testdb نام بانک اطلاعاتی اتصالی MySQL است و testTable هم نام جدول مورد نظر. MySQL ایی که در آخر عبارت ذکر شده همان نام linked server ایی است که پیشتر تعریف کردیم.
به محض سعی در اجرای این کوئری خطای زیر ظاهر میشود:
Server 'mysql' is not configured for RPC.
برای رفع این مشکل، مجددا به صفحهی خواص همان liked server ایجاد شده مراجعه کنید. در قسمت Server options دو گزینه مرتبط به RPC باید فعال شوند:
و اکنون برای کوئری گرفتن از اطلاعات ثبت شده هم از عبارت زیر میتوان استفاده کرد:
SELECT * FROM OPENQUERY(mysql, 'SELECT * FROM testdb.testtable')
در این کوئری، MySQL نام Linked server ثبت شده است و testdb هم یکی از بانکهای اطلاعاتی MySQL مورد نظر.
انتقال تمام اطلاعات یک جدول از بانک اطلاعاتی MySQL به SQL Server
پس از برقراری اتصال، اکنون import کامل یک جدول MySQL به SQL Server به سادگی اجرای کوئری زیر میباشد:
SELECT * INTO MyDb.dbo.testtable FROM openquery(MYSQL, 'SELECT * FROM testdb.testtable')
در این کوئری، MySQL همان Linked server تعریف شده است. MyDB نام بانک اطلاعاتی موجود در SQL Server جاری است و testtable هم جدولی است که قرار است اطلاعات testdb.testtable بانک اطلاعاتی MySQL به آن وارد شود.
با اطلاعات فارسی هم (در سمت SQL Server) مشکلی ندارد. همانطور که مشخص است، در اطلاعات provider string ذکر شده، مقدار charset به utf8 تنظیم شده و همچنین اگر نوع collation فیلدهای تعریف شده در MySQL نیز به utf8_persian_ci تنظیم شده باشد، با مشکل ثبت اطلاعات فارسی به صورت ???? مواجه نخواهید شد.
نکته:
اگر بانک اطلاعاتی MySQL شما بر روی local host نصب نیست، جهت فعال سازی دسترسی ریموت به آن، میتوان به یکی از نکات زیر مراجعه کرد و سپس این اطلاعات جدید باید در همان قسمت provider string مرتبط با تعریف linked server وارد شوند:
مطالب مشابه:
هیچکدام از این روشها قابل استفاده نبودند چون provider string صحیحی را نهایتا تولید نمیکنند. همچنین تمام این روشها مبتنی است بر ایجاد DSN در کنترل پنل که اصلا نیازی به آن نیست و اضافی است.
آفیس
اس کیوال سرور
توسعه وب
جاوا
دات نت فریم ورک
دبلیو پی اف و سیلور لایت
سورس کنترلها
سی و مشتقات
شیرپوینت
طراحی نرم افزار
متفرقه
محیطهای مجتمع توسعه
مسایل انسانی، اجتماعی و مدیریتی برنامه نویسی
سلام
در بکارگیری کلاس ها، ثابت ها و... علاقه زیادی دارم تا از نام کامل استفاده کنم و در بیشتر کلاس ها اصلا using ندارم. اگرچه که خطوط کمی طولانی میشن و اجبارا برای خوانایی بهتر خطوط را میشکنم ولی در زمان مرور کدها کمی راحت تر هستم. سوالم اینه که آیا این کار تضادی با کد نویسی تمیز داره یا پیشنهاد میکنید برای خلوت کردن کدها حتما فضای نام را using کنم.
تشکر
- برای حالت database first نیاز به VS 2013 دارید تا از کلیه امکانات EF 6 استفاده کنید (یا باید به روز رسانی خاصی را برای VS 2012 نصب کنید). حالت Code first مستقل است از IDE (یک مزیت دیگر).
Entity Framework Designer همراه با VS 2012 فقط از EF 5 پشتیبانی میکند (در حالت پیش فرض) و از تغییرات انجام شده در EF 6 آگاه نیست. به همین جهت اگر با VS 2012 بخواهید با EF6 کار کنید (در حالت database first) باز هم همان اسمبلی قدیمی System.Data.Entity.dll را مورد استفاده قرار میدهد که در EF 6 اصلا کاربردی ندارد و با آن یکی شده است.
البته در کل میتونید با VS 2012 هم در حالت database first با EF 6 کار کنید ولی نیاز به یک سری تغییرات دستی خواهید داشت (EF قدیمی و همچنین اسمبلی اضافی یاد شده را باید دستی حذف کنید) و به علاوه از بهبودهای جدید آن (در حالت پیش فرض و بدون به روز رسانی) محروم خواهید بود.
Entity Framework Designer سورس باز نیست (برخلاف هسته EF) و جزئی از VS.NET است. قرار است در آینده این افزونه را هم سورس باز کنند تا بتوانند مستقل از چرخه طول عمر VS.NET، خود EF Database first را نیز به روز کنند.
ولی در کل اگر از Code first استفاده میکنید، EF6 حتی با VS 2010 هم سازگار است.
- زمانیکه با یک ORM کار میکنید (فرقی نمیکند به چه اسمی)، لایه DAL همان ORM هست. (دست به اختراع لایههای اضافی نزنید)
نصب و راه اندازی مقدماتی Full Text Search
بررسیهای مقدماتی
ابتدای کار نیاز است بررسی کنیم آیا افزونهی Full Text Search، به همراه SQL Server نصب شدهاست یا خیر. برای این منظور کوئری ذیل را اجرا کنید:
select SERVERPROPERTY('IsFullTextInstalled');
instance features -> database engine services -> Full Text
راه اندازی سرویس Full Text Search
پیش از ادامهی بحث، به کنسول سرویسهای ویندوز مراجعه کرده و مطمئن شوید که سرویس SQL Full-text Filter Daemon Launcher MSSQLSERVER نیز در حال اجرا است. در غیراینصورت با خطای ذیل مواجه خواهید شد:
SQL Server encountered error 0x80070422 while communicating with full-text filter daemon host (FDHost) process.
sp_fulltext_service 'restart_all_fdhosts'
چه نوع دادههایی را میتوان توسط FTS ایندکس کرد؟
با استفاده از امکانات FTS میتوان کلیه ستونهایی را که دارای نوعهای ذیل باشند، ایندکس کرد:
char, nchar, varchar, nvarchar, text, ntext, image, xml, varbinary(max)
همچنین FTS برای پردازش این فایلهای باینری و ایندکس کردن اطلاعات آنها، نیاز به افزونههایی به نام IFilters دارد. کار این فیلترها استخراج متن بدون فرمت، از فایلهای باینری مرتبط و ارائهی آنها به موتور FTS میباشد.
نصب فیلترهای مخصوص FTS آفیس
اگر علاقمند هستید که بدانید در حال حاضر چه تعداد فیلترهای FTS بر روی سیستم شما نصب شدهاست، کوئری ذیل را اجرا نمائید:
exec sys.sp_help_fulltext_system_components 'filter';
فیلترهای آفیس را جداگانه نیز میتوانید دریافت و نصب کنید (بدون نیاز به نصب کامل آفیس بر روی سرور):
این فیلترها تا نگارش 2013 آفیس را نیز پشتیبانی میکنند و آگر آپدیت ویندوز نیز روشن باشد، سرویس پک 2 آن را نیز دریافت خواهید کرد.
پس از اینکه فیلترها را نصب کردید، باید آنها را در وهلهی جاری SQL Server ثبت کرد:
exec sys.sp_fulltext_service 'load_os_resources', 1; EXEC sp_fulltext_service 'update_languages'; EXEC sp_fulltext_service 'restart_all_fdhosts';
select * from sys.fulltext_document_types;
فیلترهای فوق علاوه بر اینکه امکان FTS را بر روی کلیه فایلهای مجموعه آفیس میسر میکنند، امکان جستجو FTS را بر روی خواص ویژه اضافی آنها، مانند نام نویسنده، واژههای کلیدی، تاریخ ایجاد و امثال آن نیز به همراه دارند.
FTS چگونه کار میکند؟
زبانهای پشتیبانی شده توسط FTS را توسط کوئری ذیل میتوانید مشاهده کنید:
select lcid, name from sys.fulltext_languages order by name;
word-breakers تک تک کلمات را (که به آنها token نیز گفته میشود) تشخیص داده و سپس FTS آنها را با فرمتی فشرده شده، درون ایندکسهای مخصوص خود ذخیره میکند.کار stemmers تولید حالات inflectional (صرفی) یک کلمه بر اساس دستور زبانی مشخص است.
اهمیت آنالیز inflectional، در اینجا است که برای مثال اگر در متنی واژهی jumps وجود داشت و کاربر در حین جستجو، jumped را وارد کرد، FTS بر اساس دستور زبان مورد استفاده، پیشتر، حالات مختلف صرفی jump را ذخیره کردهاست و امکان انجام یک چنین کوئری پیشرفتهای را پیدا میکند.
نصب و فعال سازی Semantic Language Database
کار TFS تنها به خرد کردن واژهها و آنالیز صرفی آنها خلاصه نمیشود. در مرحلهی بعد، انجام Statistical semantic search میسر میشود. در اینجا SQL Server بر اساس آمار واژههای کلیدی استخراج شده، توانایی یافتن متونی مشابه و یا مرتبط را پیدا میکند. Semantic Search جزو تازههای SQL Server 2012 است.
برای اینکار نیاز است بانک اطلاعاتی Semantic language statistics نیز نصب شود. برای اطمینان از نصب بودن آن، کوئری ذیل را اجرا کنید:
select * from sys.fulltext_semantic_language_statistics_database;
x64\Setup\SemanticLanguageDatabase.msi x86\Setup\SemanticLanguageDatabase.msi
پس از آن نیاز است این بانک اطلاعاتی را Attach و همچنین ثبت کرد:
CREATE DATABASE semanticsdb ON ( FILENAME = 'D:\SQL_Data\SemanticLanguageDatabase\semanticsdb.mdf' ) LOG ON ( FILENAME = 'D:\SQL_Data\SemanticLanguageDatabase\semanticsdb_log.ldf' ) FOR ATTACH GO EXEC sp_fulltext_semantic_register_language_statistics_db @dbname = N'semanticsdb' GO
پس از مراحل فوق، اگر مجددا کوئری یاد شده بر روی sys.fulltext_semantic_language_statistics_database را اجرا کنید، یک سطر خروجی خواهد داشت.
استفاده از چندین Context در EF 6 Code first
- ORMها صرفا کارهایی را قادر به انجام هستند که بانک اطلاعاتی مورد استفاده پشتیبانی میکند. برای نمونه در SQL Server امکان تهیه رابطه بین دو جدول از دو بانک اطلاعاتی مختلف وجود ندارد. منظور مثلا ایجاد کلید خارجی بین جداول دو بانک اطلاعاتی مختلف است و نه نوشتن کوئری بین آنها که از این لحاظ مشکلی نیست.
A FOREIGN KEY constraint can reference columns in tables in the same database or within the same table
- هدف از پشتیبانی چند Context در EF 6، تلفیق اینها با هم در قالب یک بانک اطلاعاتی است (مطلب فوق).
- همچنین در EF 6 میتوان چندین Context را به چندین بانک اطلاعاتی مختلف با رشتههای اتصالی متفاوت، انتساب داد. مباحث آغاز بانکهای اطلاعاتی هر کدام جداگانه عمل کرده و مستقل از هم عمل میکنند.
یک مثال جهت اجرا و آزمایش:
Sample25.cs
- اگر میخواهید به انعطاف پذیری Linked servers برسید (مثلا در طی یک کوئری و نه چند کوئری از جداول دو بانک اطلاعاتی مختلف در دو سرور متفاوت کوئری بگیرید)، نیاز خواهید داشت مثلا View یا SP تهیه کنید و سپس اینها را در برنامه مورد استفاده قرار دهید. Viewها با استفاده از T-SQL میتوانند کوئری واحدی از چند بانک اطلاعاتی تهیه کنند. اینبار برنامه هم نهایتا به یک بانک اطلاعاتی متصل میشود و برای آن اهمیتی ندارد که View یا SP به چه نحوی تهیه شده و با چند بانک اطلاعاتی کار میکند.
- تراکنشهای توزیع شده هم نیاز به تنظیمات خاصی در SQL Server دارند و باید MSDTC راه اندازی و تنظیم شود: (^). در غیراینصورت پیام خطای The underlying provider failed on Open. MSDTC on server is unavailable را دریافت خواهید کرد. بعد از آن باید از TransactionScope برای کار همزمان با چند Context استفاده کنید.
- تمام اکانتهای مدیریتی توکار SQL Server را حذف کردهاید (یا برایتان حذف کردهاند).
- بجز کاربر SA، تمام کاربران را از نقش SYSADMIN حذف کردهاید؛ شامل تمام اکانتهای ویندوزی و همچنین خود SQL Server.
- پسورد SA را هم فراموش کردهاید یا ندارید.
خوب، الان چکار میخواهید بکنید؟!
احتمالا نصب مجدد سرور را پیشنهاد دهید یا بانک اطلاعاتی Master را بازسازی کنید که در هر دو حالت تمام تنظیمات سرور را از دست خواهید داد. روش دیگری هم بدون از دست دادن تنظیمات سرور وجود دارد که در ادامه آنرا بررسی خواهیم کرد.
افزودن یک اکانت مدیریتی جدید به SQL Server
اگر دسترسی کامل مدیریتی خود را به SQL Server از دست دادهاید باید ابتدا به آن سرور لاگین کنید؛ با این فرض که کاربر وارد شده به سیستم، جزو local administrators group است.
C:\>sqlcmd -S . 1> create login [MachineName\TestUser] from windows; 2> go 1> exec sp_addsrvrolemember 'MachineName\TestUser','sysadmin' 2> go 1> select is_srvrolemember('sysadmin', 'MachineName\TestUser') 2> go ----------- 1 (1 rows affected) 1>
الف) اجرای sqlcmd با پارامتر S و مشخص سازی وهلهی مورد نظر
البته حالت کامل آن در صورتیکه از وهلهی پیش فرض استفاده نمیکنید SQLCMD –S Server_Name\Instance_Name است. S نیز در اینجا باید با حروف بزرگ نوشته شود.
ب) create login را بر روی یکی از اکانتهای محلی سیستم اجرا کنید. مثلا MachineName\administrator یا هر اکانت موجود دیگری که لازم است. نام آن نیز باید حتما به شکل server_name\user_name باشد.
در حین استفاده از sqlcmd، هر فرمان زمانی اجرا میشود که در سطر پس از آن، یک go نوشته شده و enter شود.
ج) سپس توسط sp_addsrvrolemember به این اکانت اضافه شده، دسترسی sysadmin بدهید.
برای آزمایش آن فقط کافی است از متد is_srvrolemember برای کوئری گرفتن استفاده کنید و یا سعی کنید توسط اکانت اضافه شده، به SQL Server لاگین کنید. این اکانت اکنون در قسمت Security/logins قابل مشاهده است.
اگر نمیخواهید از اکانتهای ویندوزی استفاده کنید، create login را به نحو ذیل مقدار دهی کنید:
C:\>sqlcmd -S . 1> use master 2> go Changed database context to 'master'. 1> create login test_user with password='123#123' 2> go 1> exec sp_addsrvrolemember 'test_user','sysadmin' 2> go 1>
استفاده یا عدم استفاده از یک تکنولوژی یا ابزار خاص، به پارامترهای مختلفی از جمله ابعاد پروژه، مهارت و دانش اعضای تیم، ماهیت پروژه، پلتفرم اجرا، بودجهی پروژه، مهلت تکمیل پروژه و تعداد نفرات تیم بستگی دارد. بنابراین واضح است پیچیدن یک نسخهی خاص، برای همهی سناریوها امکان پذیر نیست؛ اما شرایطی وجود دارد که استفاده یا عدم استفاده از این ابزارهای تکنولوژیک منطقیتر مینمایند.
Stored Procedure (که از این به بعد برای ایجاز، SP نوشته خواهد شد) هم از قاعده فوق مستثنی نیست و در صورت انتخاب صحیح میتواند به ارائهی محصول نهایی با کیفیتتری در زمان کوتاهتری کمک کند و در صورت انتخاب ناآگاهانه ممکن است باعث شکست یک پروژه (بخصوص در بلند مدت) شود.
تاریخچه
SQL توسط شرکت IBM در اوایل دهه 70 میلادی ایجاد شد. با اوج گرفتن زبانهای رویهای، SQL هم چندان از این قافله عقب نماند که منجر به پذیرش SP به عنوان یک استاندارد، در دهه 90 میلادی و پیاده سازی تدریجی آن توسط غولهای سازنده دیتابیس شد (رجوع فرمایید به ^ و ^). این فاصله 20 ساله باعث غنیتر شدن SQL شد و وجود SP - به معنی انتقال مدل برنامه نویسی رویهای به SQL - بخشی از مشکلات قبلی کار با کوئریهای پشت سر هم و خام را حل کرد. از سال 2000 میلادی به بعد، ORMهای قدرتمندی از جمله Hibernate و پیاده سازیهای مختلفی از Active Record و Entity Framework متولد شدند. بنابر این تقدم و تاخّرهای زمانی، بدیهی است اغلب مزایای SP نسبت به Raw SQL Query و اغلب معایب آن نسبت به ORMها باشد.
بنظر میرسد برای پاسخ به سوال اصلی این مطلب، ناگزیر به مقایسه SP با رقبای دیرینهاش هستیم. با برشمردن معایب و مزایای SP میتوان به نتیجهی منطقیتری رسید. البته باید در نظر داشت صرف استفاده از SP به معنای بهرهمند شدن از مزایای آن و صرف استفاده نکردن از آن هم بهرهمندی از رقبای آن نیست. چگونگی استفاده یک ابزار، مهمتر از خود ابزار است.
معایب SP
- دستورات Alter Table ، Add Column و Drop Column به این سادگیها هم نیستند؛ ممکن است به یکی از جداول دیتابیس دو ستون اضافه یا از آن حذف شوند. مجبوریم تمامی SPها را بخصوص Insert و Update متناظر با جدول را تغییر دهیم که این تغییرات ممکن است بصورت زنجیرهوار به سایر SPها هم سرایت کند. حال شرایطی را در نظر بگیرید که تعداد SPهای شما به چند ده و یا حتی به چند صد عدد و بیشتر، رسیده باشد که این به معنی زحمت بیشتر و تغییرات پر هزینهتر است.
- احتمال کند شدن ماشین سرویس دهنده در اثر اجرای تعداد
زیادی SP ؛ چناچه بخش زیادی از منطق برنامه از طریق SP اجرا شود، سرور دیتابیس موظف به اجرای آنهاست. اما در صورتیکه منطق،
در کد برنامه قرار داشته باشد، امکان توزیع آن بر روی سرورهای مجزا و یا حتی ماشین
کلاینت وجود خواهد داشت. امروزه اکثر کلاینتها به دیتابیسهای سبک و سریعی مجهز شدهاند. بنابراین در صورت امکان چرا بار پردازشی را به عهده آنها نگذاریم؟!
- یکپارچگی کمتر؛ تقریبا همه اپلیکیشنها نیازمند
ارتباط با سایر سیستمها هستند. اگر بخشهای زیادی از منطق برنامه درون SP مخفی شده باشند، این نقطه تلاقی بین سیستمی، احتمالا
درون خود دیتابیس قرار میگیرد و این به معنی ایجاد SP های بیشتر، افزودن
پارامترهای بیشتر، توسعه SPهای قبلی و بطور
خلاصه اعمال تغییرات بیشتر، که منتج به قابلیت نگهداری کمترخواهد شد.
- انعطاف پذیری کمتر؛ در یک شرایط ایده آل، عملکرد اپلیکیشن، مستقل از دیتابیس است. اگر نیاز به تغییر دیتابیس، مثلا از اوراکل به Microsoft SQL Server وجود داشته باشد، نیاز به بازنویسی و انتقال فانکشنها و SP ها محتمل است و از آنجائیکه که با وجود استانداردها، دیتابیسهای مختلف، معمولا در Syntax دستورات، تفاوتهای فاحشی دارند، هر چه کد بیشتری در SP ها باشد، نیاز به انتقال و تبدیل بیشتری وجود دارد.
- عدم وجود بازخورد مناسب؛ بسیاری از اوقات در صورت بروز اشکالی در حین اجرای یک SP، فقط با یک متن ساده بصورت Table has no rows و یا error مواجه میشویم. چنین خطاهایی هنگام دیباگ اصلا خوشایند نیستند. MS SQL در این بین بازخوردهای مناسبی را ارائه میکند. اگر تجربه کار با سایر دیتابیسها را داشته باشید، اهمیت بازخوردهای مناسب، ملموستر خواهد بود.
- کد نویسی سختتر؛ نوشتن کد SQL معمولا در همان IDE اپلیکیشن انجام نمیشود. جابجایی مداوم بین دو IDE ، دیباگ و کد نویسی از طریق دو اینترفیس مجزا، اصلا ایدهال نیست.
- SP منطق را بیش از حد پنهان میکند؛ حتی با دانستن نام صحیح یک SP، باز هم تصویری از پارامترهای ارسالی به آن و نتیجه برگشتی نخواهیم داشت. نمیدانیم نتیجه حاصل از اجرای SP ما مقداری را برمیگرداند یا خیر؟ در صورت وجود برگشتی، یک Cursor است یا یک مقدار؟ اگر Cursor است شامل چه ستونهایی است؟
- SP نمیتواند یک شیء را به عنوان آرگومان بپذیرد؛ بنابراین احتمال کثیف شدن کد به مرور افزایش پیدا میکند و بدتراز آن، در صورت ارسال اشتباه یک پارامتر، یا عدم تطابق تعداد پارامترها، مجبور به بررسی تمام آنها بصورت دستی هستیم. برای مثال دو قطعه کد زیر را با هم مقایسه کنید:
INSERT INTO User_Table(Id,Username,Password,FirstName,SureName,PhoneNumber,x,Email) VALUES (1,'VahidN','123456','Vahid','Nasiri','09120000000','vahid_xxx@example.com')
و معادل آن در یک ORM فرضی:
public void Insert(User user) { _users.Insert(user); db.Save(); }
بهوضوح قطعه کد sql، قبل از خوب یا بد بودن، زشت است. همچنین پارامتر x آن که فرضاً به تازگی اضافه شده، مقداری را دریافت نکرده و باعث بروز خطا خواهد شد.
- نبود Query Chaining؛ یکی از ویژگیهای جذاب ORMهای امروزی، امکان تشکیل یک کوئری با قابلیت خوانایی بالا و افزودن شرطهای بیشتر از طریق الگوی builder است. قطعه کد زیر یک SP برای جستجوی داینامیک نام و نام خانوادگی در یک جدول فرضی به اسم Users است:
public ICollection<User> GetUsers(string firstName,string lastName,Func<User, bool> orderBy) { var query = _users.where(u => u.LastName.StartsWith(lastName)); query = query.where(u => u.FirstName.StartsWith(firstName)); query = query.OrderBy(orderBy); return query.ToList(); }
در مقایسه با معادل SP آن:
CREATE PROCEDURE DynamicWhere @LastName varchar(50) = null, @FirstName varchar(50) = null, @Orderby varchar(50) = null AS BEGIN DECLARE @where nvarchar(max) SELECT @where = '1 = 1' IF @LastName IS NOT NULL SELECT @Where = @Where + " AND A.LastName LIKE @LastName + '%'" IF @FirstName IS NOT NULL SELECT @Where = @Where + " AND A.FirstName LIKE @FirstName + '%'" DECLARE @orderBySql nvarchar(max) SELECT @orderBySql = CASE WHEN @OrderBy = "LastName" THEN "A.LastName" ELSE @OrderBy = "FirstName" THEN "A.FirstName" END DECLARE @sql nvarchar(max) SELECT @sql = " SELECT A.Id , A.AccountNoId, A.LastName, A.FirstName, A.PostingDt, A.BillingAmount FROM Users WHERE " + @where + " ORDER BY " + @orderBySql exec sp_executesql @sql, N'@LastName varchar(50), @FirstName varchar(50) @LastName, @FirstName END
حاجت به گفتن نیست که قطعه کد اول چقدر خواناتر، انعطاف پذیرتر، خلاصهتر و قابل نگهداریتر است.
- نداشتن امکانات زبانهای مدرن؛ زبانها و IDEهای مدرن، امکانات قابل توجهی را برای نگهداری بهتر، انعطاف پذیری بیشتر، مقیاس پذیری بالاتر، تست پذیری دقیقتر و... ارائه میکنند. به عنوان مثال:
- شیءگرایی و امکانات آن که در SP موجود نیست و در مورد قبلی معایب، به آن مختصرا اشاره شد. در نظر بگیرید اگر SQL زبانی شیء گرا بود و مجهز به ارث بری و کپسوله سازی بود، چقدر قابلیت نگهداری آن بالاتر میرفت و حجم کدهای نوشته شده میتوانست کمتر باشند.
- نداشتن Lazy Loading که باعث مصرف زیاد حافظه میشود.
- نداشتن intellisense حین فراخوانیها.
- نداشتن Navigation Property که باعث join نویسیهای زیاد خواهد شد.
- SQL در مقایسه با یک زبان مدرن ناقص بنظر میرسد و این نوشتن کد آن را سختتر میکند.
- نداشتن امکان تغییر منطقی نام جداول و ستون ها
- مدیریت تراکنشها بصورت دستی، حال آنکه با الگوی Unit Of Work این مشکل در یک ORM قدرتمند مثل EF حل شده است.
- زمان بر بودن نوشتن SP؛ گاهی نوشتن یک تابع در یک ORM یا بعضا نوشتن یک کوئری SQL کوتاه در یک رشته متنی، سادهتر از نوشتن کد SP است. آیا برای هر وظیفه کوچک در دیتابیس، نوشتن یک SP ضروری است؟
مزایای SP :
- کمتر کردن Round Trips در شبکه و متعاقبا کاهش ترافیک شبکه؛ اگر از یک فراخوانی استفاده کنیم، کاهش Round Tripها تاثیر چندانی نخواهد داشت. همچنین ارسال یک کوئری کامل، نسبت به ارسال فقط اسم SP و پارامترهای آن، پهنای باند بیشتری اِشغال میکند. البته در یک شبکه با سرعت قابل قبول، بعید است این دو مزیت محسوس باشند؛ اما به هر حال برای موارد خاص، دو مزیت محسوب میشوند. نکته دیگر آنکه بدلیل Pre-Compiled بودن SPها و همچنین کَش شدن Execution Plan آنها، اندکی با سرعت بالاتری اجرا میشوند.
- امکان چک کردن سینتکس قبل از اجرای آن؛ در مقایسه با Raw Query مزیت محسوب میشود.
- امکان به اشتراک گذاری کد؛ برای پروژههایی که چندین اپلیکیشن با چندین زبان برنامه نویسی مختلف در حال تهیه هستند و نیازمند دسترسی مستقیم به دادهها با سرعت به نسبت بالاتری هستند، SP میتواند یک راه حل ایده آل محسوب شود. بجای پیاده سازی منطق برنامه در هر اپلیکیشن بصورت جداگانه و زحمت کدنویسی هرکدام، میتوان از SP استفاده کرد. هرچند امروزه معمولا برای حل این مشکل، API های مشترک معماری Restful ارجحیت دارد.
- کمک به ایجاد یک پَک؛ در یک زیر سیستم با نیازمندی مشخص که اعمال تغییرات در آن محتمل نمیباشد نیز SP میتواند یک گزینه مناسب به حساب آید. مثلا یک سیستم Membership را در نظر بگیرید که در پروژههای مختلف شما مورد استفاده قرار خواهد گرفت. برای مثال میشود یک سیستم Membership سفارشی را با امکان Hash پسورد و رمز کردن دادههای حساس، به کمک SP و Function های مناسب فراهم کرد و در واقع بین Application Login و Data Logic تمایز قائل شد. شخصا معماری Restful را به این روش هم ترجیح میدهم.
- بهرمند شدن از امکانات بومی SQL ؛ به عنوان نمونه برای ترانهاده کردن خروجی یک کوئری میتوان از فانکشن Pivot استفاده کرد. یا فانکشنهای تحلیلی Lead و Lag (لینک مستندات اوراکل این دو فانکشن به ترتیب در ^ و ^ ) که بنظر نمیرسد هنوز معادل مستقیمی درORM ها داشته باشند.
- تسلط و کنترل بیشتر و دقیقتر بر کوئری نهایی؛ گفته میشود SP و عبارات SQL در دیتابیس، حکم assembly را در سایر زبانها دارند. بنابراین با SP میتوان عبارات SQL و نحوه اجرای آن را در دیتابیس، بطور کامل تحت فرمان داشت. این در حالی است که هر یک از ORMها دستورات زبان برنامه نویسی مبداء را به یک عبارت SQL ترجمه میکنند که این عبارت چندان تحت کنترل برنامه نویس نیست و بیشتر به مدل کاری ORM بستگی دارد.
- امکان join بین دو یا چند دیتابیس مجزا؛ حال آنکه امکان join بین دو Context در ORM ها وجود ندارد. بعلاوه اگر دو دیتابیس مدنظر ما روی دو سرور مجزا باشند، با SP و کانفیگ Linked Server کماکان میشود کوئری join دار نوشت.
- برای عملیاتهای Batch مناسبتر است؛ در مقام مقایسه با ORM ها که با تکنیکهای مختلفی سعی در افزایش سرعت عملیات Batch، بخصوص Insert و Update را دارند، SP با سرعت قابل قبولتری اجرا میشود.
- عدم نیاز به یادگیری سینتکس و ابزاری جدید؛ موارد
بسیاری وجود دارند که فرصت یادگیری تکنولوژی جدیدی مثل یک ORM و یا SQL Bulk و حتی کتابخانههای ثالث مبتنی بر این ابزارها وجود ندارند و ممکن است مجبور شوید برای باقی ماندن در بازار رقابتی، از
دانستههای قبلی خود استفاده کنید .
- تخصصیتر کردن وظایف؛ برنامه نویسهای دیتابیس به صورت تخصصی اقدام به تحلیل روابط و ایندکسها میکنند، دیتابیس را ایجاد و نرمال سازی مینمایند، SP های متناسب را میسازند و به بهترین شکل Optimize و در آخر تست میکنند.
- امنیت به نسبت بالاتر؛ میتوان مجوز اجرای SP را به یک کاربر اعطا کرد، بدون آنکه مجوز دسترسی به جداول مورد استفاده در آن SP را داد. همچنین نسبت به کوئریهای پارامتری نشده، SQL ارجیحت دارند چون احتمال آسیب پذیری در مقابل SQL Injection را کمتر میکنند.
نتیجهگیری
اگرچه SP ها برای پردازش دادهها آنقدر هم که در وبلاگها میخوانیم بد نیستند، اما سوء استفاده از آن، مشکلات عدیدهای را ایجاد خواهد کرد. با توجه به روند تغییرات تکنولوژیهای دسترسی به دادهها و معماریهای مدرن بنظر میرسد SP در بهترین حالت، ابزار مناسبی برای انجام عملیات CRUD است و نه بیشتر؛ مگر در مواردی خاص که به تشخیص شما نیاز به استفاده بیشتر از آن وجود داشته باشد.