در نوشته های پیشین از ویژگی Linq-to-Entity برای پرس و جو بر روی مدل Entity framework گفته ایم. Entity Framework ابزاری است که برنامه نویس را از انجام سر راست پرس و جوهای SQL بی نیاز می کند ولی بازهم شاید نیاز باشد تا بخواهید به گونه سر راست، دستور SQL را نوشته و با آن و بدون Entity Framwork با پایگاه داده همکنشی (تعامل) داشته باشید.

در نوشته های پیشین نشان دادیم که متد ()Add را برای افزدون یک سطر و ()AddRange را برای افزودن چندین سطر به جدول به کار می بریم. بنابراین این دو متد کاربرد دستور INSERT در SQL را دارند. همچنین نشان دادیم که بدست نام ویژگی DbSet درون کلاس Contect، می توانیم همه سطرهای جدول آن را واکشی کنیم که همان کاربرد دستور SELECT * FROM در SQL است.

در کدهای زیر نمونه ساده ای از کاربرد Linq to Entity را می بینید که از ویژگی های Linq برای انجام پرس و جو بر روی جدول های پایگاه داده با کمک گیری از کلاس های موجودیت (Entity Class) کمک گرفته ایم. در آن همه بلاگ هایی پیدا می شوند که در آغاز نام آنها حرف B باشد. دومین کد زیر دستور SQL همسان با دستورهای سی شارپ را نشان می دهد. بنابراین در این نوشته می خواهیم ویژگی هایی از Dot Net را نشان دهیم که با آنها می توانیم دستورهای خام SQL (یا Raw SQL) را درون Entity Framework انجام دهیم.

کاربرد ویژگی های Dot Net برای انجام SQL در Entity Framework

رویه های ذخیره شده (Stored Prcedure)، ویژگی هایی هستند که به برنامه نویس های پایگاه داده اجازه می دهد تا بتوانند رویه هایی (Procedure) را درون پایگاه داده و بدست T-SQL در SQL Server و PL/SQL در اوراکل بنویسند و سپس آنها را بدست برنامه های دیگر به زبان های برنامه نویسی مانند سی شارپ یا پی اچ پی یا از درون خود پایگاه داده فراخوانی شوند. این رویه ها درون Data Dictionary پایگاه داده نگهداری می شوند.

بنابراین یکی از کاربردهای انجام سر راست (مستقیم) دستورهای SQL در Entity Framework، فراخوانی رویه های ذخیره شده در رویکرد Code First است، زیرا در Entity Framework هم اکنون از نگاشت (Mapping) ویژگی Linq to Entity به رویه دخیره شده پشتیبانی نمی شود. در زیر نام سه روش انجام سر راست دستورهای SQL در Entity Framework فهرست شده است.

  • ()DbContext.DbSet.SQLQuery
  • ()DbContext.Database.ExecuteSqlCommand و ()DbContext.Database.ExecuteSqlCommandAsync
  • ()DbContext.Database.SQLQuery

روش نخست – متد ()SQLQuery از کلاس DbSet

همانگونه که می دانید کلاس Context دارای ویژگی های <DbSet<Entity است که Entity نام کلاس موجودیت است که یک جدول پایگاه داده را درون مدل Entity Framework نشان می دهد. یکی از روش های انجام دستورهای SQL، به کار بردن متدی به نام ()SQLQuery است که می توان به این متد با کمک نام کلاس موجودیت دسترسی داشت.

در کدهای زیر گمان کنید که CompantEntities نام کلاس Context است که پایگاه داده ای در برگیرنده چندین جدول مانند Employee را نشان می دهد. متغیر context نیز نمونه ای از کلاس CompanyEntities است که از آن برای دسترسی به ویژگی های <DbSet<Entity کمک می گیریم. یکی از جدول های این پایگاه داده، Employee نام دارد، پس درون کلاس Context باید ویژگی به گونه <DbSet<Employee شناسانده (تعریف) شده باشد. بنابراین درکدهای زیر، پس ساخت (ایجاد) نمونه ای از کلاس Context، از نام کلاس موجودیت (Employee) برای دسترسی به متد ()SQLQuery کمک گرفته ایم تا یک دستور SELECT را سر راست (مستقیم) وبدون Linq to Entity انجام دهیم.

در بالا برگشتی پرس و جوی فرستاده شده به متد ()SQLQuery در پایان به یک List از گونه کلاس Employee دگرگون (تبدیل) شده است. بنابراین می توانیم این List را در هر جای دیگری پردازش کنیم. برای نمونه می توانیم در فایل های نما در وب سایت های ASP.NET MVC نمایش دهیم. همچنین می توانیم دیگر پرس و جوها مانند INSERT و UPDATE و DELETE را نیز انجام دهیم.

انجام رویه ذخیره شده

در کد زیر گمان کنید که یک رویه ذخیره شده داریم که فهرست همه کارمندان را برگشت می دهد. در واقع برنامه سی شارپ، سر راست با پایگاه داده SQL Server ارتباط برقرار کرده و سپس این کد درون پایگاه داده انجام شده و سپس سطرها برگشت داده می شوند و در پایان خروجی به گونه List سی شارپ دگرگون (تبدیل) می شود.

کد زیر نمونه دیگری را نشان داده است که در آن مقداری به رویه دخیره شده فرستاده می شود. در این کد به گونه دستی متغیری به نام employeeId با مقدار پیشفرض 1 را نوشته ایم و سپس درون متد ()SQLQuery، آرگومان نخست نام رویه ذخیره شده و آرگومان دوم، مقدار تعیین شده برای ورودی رویه ذخیره شده است.

گونه های یکمینه (اولیه)

در روش و کد بالا، برگشتی متد ()SQLQuery برابر با گونه ای از کلاس موجودیت (Entity) است که سپس ما در اینجا آن را به یک List از گونه کلاس Entity دگرگون (تبدیل) کرده ایم. در این بخش می خواهیم با همان کد بالا نشان دهیم که می توانیم با ()SQLQuery، گونه یکمینه (اولیه یا primitive types) را مانند int, float را برگشت دهیم.

همچنین می توانیم همانند کد زیر که List از نام بلاگ ها را بر می گرداند، دیگر گونه ها مانند string را نیز به کار ببریم. بنابراین هم می توانیم برگشتی ()SQLQuery را از گونه کلاس های موجودیت و هم از گونه های پایه زبان برنامه نویسی مانند int و float و string برگشت دهیم.

متد ()SqlQuery از کلاس Database

همانگونه که گفتیم می توانیم به کمک نام هر کدام از ویژگی های <DbSet<Entity می توانیم متد ()SqlQuery را برای انجام سر راست یک دستور SQL بر روی یک جدول پایگاه داده به کار ببریم. این روش زمانی سودمند است که بخواهیم دستورهای SQL را بر روی یک جدول انجام دهیم ولی می توانیم روش دیگری و آن هم کلاس Databse را به کار ببریم تا بتوانیم کوئری را بر روی پایگاه داده ای انجام دهیم که به دست کلاس Context اداره می شود.

در کد زیر دو نمونه از کاربرد متد ()Database.SqlQuery را می بینید که در آن تک سطر برگشتی از گونه string است. نگاه کنید که نخست یک نمونه از کلاس Context به نام context ساخته ایم و سپس از آن به کلاس Database و سپس به متد ()SqlQuery دسترسی پیدا کرده ایم.

همچنین در دو کد زیر، دستور دیگر از عملیات چهارگانه CRUD، یعنی DELETE نیز نشان داده شده است. همچنین می توانید دستورهای دیگر، یعنی INSERT برای درج داده ها و UPDATE برای بروز رسانی داده ها را نیز به کار ببرید. دستورهای دیگر همانند Join چندین جدول و یا عملگرهای دیگر مانند UNION را نیز انجام دهید ولی نباید از این روش برای ساخت جدول تازه کمک بگیرید، بلکه بهتر است همان کلاس های موجودیت و انجام مهاجرت جدوا یا جدول های تازه را به کار ببرید.

نمایش داده از چندین جدول – SQL Join – بخش نخست

نمایش داده از چندین جدول – SQL Join – بخش دوم

نمایش داده از چندین جدول – SQL Join – بخش سوم

اجتماع، اشتراک و تفریق در SQL

زیر کوئری ها در SQL – بخش یکم

زیر کوئری ها در SQL – بخش دوم

متد ()ExecuteSqlCommand از کلاس Database

این متد برای انجام پرس و جوهای INSERT و UPDATE و DELETE به کار گرفته می شود. این متد یک شماره برابر با شمارگان (تعداد) سطرهای تاثیر یافته از دستور را برگشت می دهد. برای نمونه در کد DELETE بالا، می بینید که گونه متغیر result برابر با int است، که شمارگان (تعداد) سطرهای پاک شده را بر می گرداند. در اینجا نیز چنین است و متغیری که برگشتی این متد را نگه می دارد باید از گونه int بشد.

در کد زیر دو نمونه از کاربرد متد ()Database.SqlQuery را می بینید که در آن تک سطر برگشتی از گونه string است. نگاه کنید که نخست یک نمونه از کلاس Context به نام context ساخته ایم و سپس از آن به کلاس Database و سپس به متد ()SqlQuery دسترسی پیدا کرده ایم.

کد زیر نمونه دیگری از کاربرد متد ()Database.ExecuteSqlCommand را نشان می دهد که از آن نخست با اتجام دستور DELETE همه سطرهای جدول دلخواه پاک می شود. سپس می خواهیم دو سطر را به جدول بیافزاییم. برای همین، نخست یک متغیر به نام sql ساخته ایم که دستور SQL را در خود نگه می دارد. می خواهیم مقدارهایی را برای دو ستون به جدول بیافزاییم، پس دو پارامتر p0@ و p1@ را نیز پس از عبارت VALUES نوشته ایم. سپس این متغیر به آرگومان یکم ()Database.ExecuteSqlCommand فرستاده شده و سپس به اندازه پارامترهای تعیین شده در متغیر sql، به آرگومان های دوم و سوم مقدارهایی فرستاده می شود. همین کار را نیز برای سطر دیگر انجام داده ایم.

سپس به شیوه ای که پیش از این گفتیم، همه سطرهای درون جدول دلخواه نمایش داده می شوند. به گفته دیگر، در این جا دیگر دستور SQL را به کار نبرده ایم، بلکه از کلاس موجودیت برای بدست آورده همه سطرها کمک گرفته ایم. درون حلقه foreach نخست همه سطرها با دستور context.EntityClassName بدست می آیند و سپس، در هر گام یکی از سطرهای آن درون متغیر table_row ریخته شده و سپس در برنه حلقه، سطرهای آن با نام نام ستون ها نمایش داده می شوند.

تنها چیزی که درباره کد بالا می ماند، متغیر rowCount است که در بَند (خط) ۱۳ نوشته ایم و دوباره آن را در بند ۱۵ به کار برده ایم. گفتیم که برگشتی متد ()Database.ExecuteSqlCommand شماره ای است که شمارگان (تعداد) سطرهای تاثیر یافته در جدول را نشان می دهد. در بند ۱۳ یک سطر درج شده، پس شماره ۱ برگشت داده می شود و در بند ۱۵ سطر دیگری درج می شود، پس باید شماره ۱ دوباره برگشت داده شده و به مقدار پیشین درون متغیر افزوده شود تا در پایان شمارگان سطرهای تاثیر یافته را داشته باشیم.