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

اجرای عملکرد CRUD پایه با Entity Framework در برنامه ی ASP.NET MVC

نمونه برنامه ی وب دانشگاه Contoso چگونگی ایجاد برنامه های ASP.NET MVC 5 را با استفاده از Framework 6 Code First و Visual Studio 2013 توضیح می دهد.

در آموزش قبل یک برنامه ی MVC ایجاد کردید که با استفاده از Entity Framework و SQL Server LocalDB داده را ذخیره کرده و نمایش می دهد. در این آموزش کد CRUD را مرور کرده و شخصی خواهید کرد (ایجاد کردن، خواندن، آپدیت کردن و حذف کردن) که MVC scaffolding آن را به طور خودکار در کنترل کننده ها و ویوها ایجاد کرده است.

نکته: اجرای الگوی مرکز برای ایجاد یک لایه ی غیرعملی بین کنترل کننده ی شما و لایه ی دسترسی داده، یک نمرین متداول می باشد. برای ساده نگه داشتن این آموزش ها و حفظ تمرکز آنها بر روی آموزش چگونگی استفاده از خود Entity Framework از منابع استفاده نمی کنند.

در این آموزش صفحات وب زیر را ایجاد خواهید کرد.

آموزش mvc

ایجاد یک صفحه با جزئیات

کد scaffolded برای ایجاد یک صفحه یIndex دانشجو، پراپرتی Enrollments را رها کرده است، زیرا این پراپرتی یک مجموعه را در خود دارد. در صفحه ی Details محتوای صفحه را در یک جدول HTML نمایش می دهید.

در Controllers\StudentController.cs روش عمل برای ویو Details از روش Find استفاده می کند تا یک ماهیت مجزای Student را بازیابی کند.

public ActionResult Details(int? id)‎
‎{‎
‎ if (id == null)‎
‎ {‎
‎ return new HttpStatusCodeResult(HttpStatusCode.BadRequest);‎
‎ }‎
‎ Student student = db.Students.Find(id);‎
‎ if (student == null)‎
‎ {‎
‎ return HttpNotFound();‎
‎ }‎
‎ return View(student);‎
‎}‎

مقدار اصلی به عنوان یک پارامتر idبه روش انتقال پیدا می کند و از route data در هایپرلینک Details وارد صفحه ی ایندکس می شود.

Rout data

Rout data داده ای است که model binder در قسمت URL، در جدول Routing پیدا کرده است. به عنوان مثال یک مسیر پیش فرض بخش های controller ،action و id را مشخص می کند.

routes.MapRoute(‎

نام: “Default”

url: “{controller}/{action}/{id}”،‎
defaults: new { controller = “Home”، action = “Index”، id = ‎UrlParameter.Optional }‎
‎);‎

در URL زیر Instructor را به عنوان یک controller و Index را به عنوان action و ۱ به عنوان id طراحی می کند. اینها مقادیر مسیر داده می باشند.

http://localhost:1230/Instructor/Index/1?courseID=2021‎

“?courseID=2021” مقدار یک ردیف رشته می باشد. اگر شما id را به عنوان مقدار یک ردیف رشته انتقال دهید، model binder نیز کار خواهد کرد. در کد زیر پارامتر id با کد پیش فرض هماهنگ است، بنابراین id به مسیر داده اضافه می شود.

@Html.ActionLink(“Select”، “Index”، new { id = item.PersonID })‎

در کد زیر courseID با یک پارامتر در مسیر پیش فرض هماهنگ نمی شود، بنابراین به عنوان یک ردیف رشته افزوده می شود.

@Html.ActionLink(“Select”، “Index”، new { courseID = item.CourseID })‎

۱٫ Views\Student\Details.cshtml را باز کنید. هر فیلد با استفاده از یک کمک کننده ی DisplayFor نمایش داده می شود، همان طور که در مثال زیر مشاهده می کنید.

‎<dt>

‎ ‎ ‎ @Html.DisplayNameFor(model => model.LastName)‎

</dt>‎

‎<dd>

‎ @Html.DisplayFor(model => model.LastName)‎

</dd>‎

۲٫ پس از فیلد EnrollmentDate و قبل از بستن برچسب &lt;/dl>، کد هایلایت شده ی زیر را برای نمایش لیستی از ثبت نام ها اضافه کنید، همان طور که در مثال زیر می بینید.

‎<dt>

‎ @Html.DisplayNameFor(model => model.EnrollmentDate)‎

</dt>‎

‎<dd>

‎ @Html.DisplayFor(model => model.EnrollmentDate)‎

</dd>‎

‎<dt>

‎ @Html.DisplayNameFor(model => model.Enrollments)‎

</dt>‎

‎<dd>

‎ <table class=”table”>

<tr>

<th>Course Title</th>‎

<th>Grade</th>‎

</tr>‎

‎ @foreach (var item in Model.Enrollments)‎

‎ {‎

<tr>

<td>

‎ @Html.DisplayFor(modelItem => item.Course.Title)‎

</td>‎

<td>

‎ @Html.DisplayFor(modelItem => item.Grade)‎

</td>‎

</tr>‎

‎ }‎

</table>‎

</dd>‎

‎ </dl>‎

‎</div>‎

‎<p>

‎ @Html.ActionLink(“Edit”، “Edit”، new { id = Model.ID }) |‎

‎ @Html.ActionLink(“Back to List”، “Index”)‎

</p>‎

پس از جایگذاری کد، اگر جایگذاری آن اشتباه است CTRL-K-D را فشار دهید تا از این طریق آن را درست کنید. این کد از طریق ماهیت ها در پراپرتی مسیریابی Enrollments گره می خورد. برای هر ماهیت Enrollment در پراپرتی، تیتر واحد و نمره بندی را نشان می دهد. تیتر واحد از ماهیت Course بازیابی می شود که در پراپرتی مسیریابی Course از ماهیت Enrollments ذخیره شده است. همه ی این داده ها در هنگام نیاز به طور خودکار از دیتابیس بازیابی می شوند. (به عبارت دیگر در اینجا از lazy loading استفاده می کنید. شما برای پراپرتی مسیریابی Courses بارگذاری eager را تعیین نکرده اید. بنابراین ثبت نام ها در همان ردیفی که دانشجویان دریافت کردند، بازیابی نشدند. در عوض اولین باری که سعی می کنید به پراپرتی مسیریابی Enrollments دسترسی داشته باشید، یک ردیف جدید برای بازیابی داده به دیتابیس ارسال می شود.

۳٫ با انتخاب تب Students و کلیک کردن بر روی لینک Details برای الکساندر کارسن، صفحه را اجرا کنید. (اگر هنگامی که فایل Details.cshtml باز است، CTRL+F5 را فشار دهید، یک خطای HTTP 400 دریافت خواهید کرد، زیرا Visual Studio سعی می کند صفحه ی Details را اجرا کند اما از لینکی که دانشجو را برای نمایش مشخص کرده است، نرسیده بود. در این مورد فقط “Student/Details” را از URL حذف کرده و دوباره سعی کنید، یا مرورگر را بسته و روی پروژه کلیک راست کنید و روی View و سپس روی View in Browser کلیک کنید.)

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

آپدیت صفحه ی Create

در Controllers\StudentController.cs کد زیر را جایگزین روش فعالیت HttpPost Create کنید تا یک بلوک try-catch اضافه کرده و ID را از Bind attribute برای روش Scaffolded حذف کنید.

‎[HttpPost]‎

‎[ValidateAntiForgeryToken]‎

public ActionResult Create([Bind(Include = “LastName، FirstMidName، ‎EnrollmentDate”)]Student student)‎
‎{‎
‎ try
‎ {‎
‎ if (ModelState.IsValid)‎
‎ {‎
‎ db.Students.Add(student);‎
‎ db.SaveChanges();‎
‎ return RedirectToAction(“Index”);‎
‎ }‎
‎ }‎
‎ catch (DataException /* dex */)‎
‎ {‎
‎ //Log the error (uncomment dex variable name and add a line ‎here to write a log.‎
‎ ModelState.AddModelError(“”، “Unable to save changes. Try ‎again، and if the problem persists see your system administrator.”);‎
‎ }‎
‎ return View(student);‎
‎}‎

این کد ماهیت Student را که توسط ASP.NET MVC اضافه شده، به مجموعه ی ماهیت Students اضافه می کند و سپس تغییرات را در دیتابیس ذخیره می کند. (Model binder اشاره به عملکرد ASP.NET MVC دارد که کار با داده ی پذیرفته شده توسط یک فرم را برای شما آسانتر می کند. یک model binder مقادیر فرم پست شده به انواع CLR را تغییر می دهد و آنها را در پارامترها به روش فعالیت تغییر می دهد. در این مورد model binder یک ماهیت Student را با استفاده از مقادیر پراپرتی از مجموعه ی Form، برای شما به عنوان نمونه می آورد.)

شما ID را از پراپرتی Bind حذف کرده اید زیرا ID مقدار اولیه ی اصلی می باشد که SQL Server در هنگام ورود ردیف به طور خودکار تنظیم خواهد کرد. ورودی از طرف کاربر مقدار ID را تنظیم نمی کند.)

نکته ی امنیتی

عبارت ValidateAntiForgeryToken کمک می کند تا از حمله های cross-site request forgery جلوگیری شود. این امر یک عبارت منطبق Html.AntiForgeryToken() نیاز دارد که بعدها خواهید دید.

عبارت Bind راهی برای محافظت در مقابل over-posting در ایجاد سناریوها می باشد. به عنوان مثال تصور کنید که ماهیت Student دارای یک پراپرتی Secret می باشد که نمی خواهید که این صفحه ی وب تنظیم کند.

public class Student
‎{‎
‎ public int ID { get; set; }‎
‎ public string LastName { get; set; }‎
‎ public string FirstMidName { get; set; }‎
‎ public DateTime EnrollmentDate { get; set; }‎
‎ public string Secret { get; set; }‎
‎ public virtual ICollection Enrollments { get; set; }‎
‎}‎

حتی اگر روی صفحه ی وب فیلد Secret ندارید، یک هکر می تواند ازابزاری مانند fiddler استفاده کند یا جاوااسکریپت بنویسد تا یک مقدار Secret را پست کند. بدون عبارت Bind محدود کردن فیلدهایی که model binder در هنگام ایجاد نمونه ی Student استفاده می کند، model binder مقدار فرم Secret را برمی گزیند و از آن برای ایجاد نمونه ماهیت Student استفاده می کند. بنابراین هر مقداری که هکر برای فیلد فرم Secret تعیین کرده است، در دیتابیس آپدیت می شود.

مقدار “OverPost” به طور موفقیت آمیزی به پراپرتی Secret از ردیف وارد شده اضافه می شود، گرچه هرگز قصد نداشتید که آن پراپرتی را تنظیم کنید. بهترین تمرین برای امنیت، استفاده از پارامتر Include با عبارت Bind در فیلدهای towhitelist می باشد. همچنین ممکن است برای فیلدهای blocklist که می خواهید خارج کنید از پارامتر Exclude استفاده کنید. وقتی که یک پراپرتی جدید به ماهیت اضافه می کنید، دلیل Include امن تر می باشد، پراپرتی جدید به طور خودکار توسط لیست Exclude محافظت نمی شود.

شما می توانید در ویرایش سناریو ها overposting جلوگیری کنید که این ویرایش که ویرایش با خواندن ماهیت از دیتابیس و فراخواندن TryUpdateModel انجام می شود. این روشی است که در این آموزش ها استفاده می شود. یک روش پیشنهادی برای جلوگیری از overposting که بسیاری از توسعه دهندگان نیز آن را ترجیح می دهند، استفاده از مدل های ویو به جای استفاده از گروه های ماهیت با دسته ی مدل می باشد. تنها پراپرتی هایی را وارد مدل ویو کنید که می خواهید آپدیت شوند. زمانی که MVC model binder به پایان رسیده است، پراپرتی های مدل ویو را به نمونه ی ماهیت کپی کنید که به طور انتخابی از ابزاری مانند AutoMapper استفاده می کنید. از db.Entry برروی نمونه ماهیت برای تنظیم وضعیت آن در حالت Unchanged استفاده کنید و سپس پراپرتی را تنظیم کنید (“PropertyName”). پراپرتی در هر ماهیتی که در مدل ویو وجود دارد به true اصلاح شده است. این روش هم در ایجاد و هم در ویرایش سناریوها استفا ده می شود.

علاوه بر عبارت Bind بلوک try-catch تنها تغییری است که به مد Scaffolded اعمال کرده اید. اگر یک اکسپشن که از DataException استخراج می شود، در هنگام ذخیره ی تغییرات اتفاق بیفتد، یک پیغام خطای کلی نمایش داده می شود. اکسپشن های DataException گاهی اوقات توسط یک چیز خارجی نسبت به برنامه اتفاق می افتند تا یک خطای برنامه نویسی، بنابراین پیشنهاد می شود کاربرها دوباره امتحان کنند. یک برنامه ی معرفی کیفیت اکسپشن را ثبت می کند، گرچه در این نمونه اجرا نمی شود.

کد Views\Student\Create.cshtml شبیه آن چیزی است که شما در Details.cshtmlمشاهده کردید، به جز اینکه کمک کننده های EditorFor و ValidationMessageFor به جای DisplayFor در هر فیلد استفاده می شوند.

در اینجا کد مربوط را مشاهده می کنید.

‎<div class=”form-group”>

‎ @Html.LabelFor(model => model.LastName، new { @class = “control-‎label col-md-2” })‎

‎ <div class=”col-md-10″>

‎ @Html.EditorFor(model => model.LastName)‎

‎ @Html.ValidationMessageFor(model => model.LastName)‎

</div>‎

</div>‎

Create.chstml نیز حاوی می باشد که با عبارت @Html.AntiForgeryToken() در کنترل کننده کار می کند که تا از حملات cross-site request forgery جلوگیری کند.

هیچ تغییری در Create.cshtml لازم نیست.

۱٫ با انتخاب تب Students و کلیک کردن برروی Create New صفحه را اجرا کنید.

۲٫ نام ها و یک تاریخ نامعتبر وارد کرده و روی Create کلیک کنید تا پیغام خطا را مشاهده کنید.

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

if (ModelState.IsValid)‎
‎{‎
‎ db.Students.Add(student);‎
‎ db.SaveChanges();‎
‎ return RedirectToAction(“Index”);‎
‎}‎

۳٫ تاریخ را به یک مقدار معتبر تغییر دهید و روی Create کلیک کنید تا دانشجوی جدید را که در صفحه ی Index ظاهر می شود، مشاهده کنید.

آپدیت روش ویرایش HTTP Post

در Controllers\StudentController.cs روش HttpGet Edit (روشی بدون عبارت HttpPost) از روش Find برای بازیابی ماهیت دانشجوی انتخابی استفاده می کند، همانطور که در روش Details مشاهده کردید. لازم نیست این روش را تغییر دهید.

به هرحال کد زیر را جایگزین روش فعالیت HttpPost Edit کنید.

‎[HttpPost، ActionName(“Edit”)]‎
‎[ValidateAntiForgeryToken]‎
public ActionResult EditPost(int? id)‎
‎{‎
‎ if (id == null)‎
‎ {‎
‎ return new HttpStatusCodeResult(HttpStatusCode.BadRequest);‎
‎ }‎
‎ var studentToUpdate = db.Students.Find(id);‎
‎ if (TryUpdateModel(studentToUpdate، “”،‎
‎ new string[] { “LastName”، “FirstMidName”، “EnrollmentDate” ‎‎}))‎
‎ {‎
‎ try
‎ {‎
‎ db.Entry(studentToUpdate).State = EntityState.Modified;‎
‎ db.SaveChanges();‎
‎ return RedirectToAction(“Index”);‎
‎ }‎
‎ catch (DataException /* dex */)‎
‎ {‎
‎ //Log the error (uncomment dex variable name and add a ‎line here to write a log.‎
‎ ModelState.AddModelError(“”، “Unable to save changes. Try ‎again، and if the problem persists، see your system administrator.”);‎
‎ }‎
‎ }‎
‎ return View(studentToUpdate);‎
‎}‎

این تغییرات بهترین تمرین امنیت را برای جلوگیری از overposting اجرا می کنند. scaffolder یک عبارت تولید کرد و ماهیت ایجاد شده به وسیله ی model binder را به ماهیت تنظیم شده با پرچم Modified، اضافه کرد. این کد دیگر پیشنهاد نمی شود زیرا عبارت Bindهمه ی داده ی از قبل موجود را که در پارامتر Include لیست نشده اند، پاک می کند. در آینده کنترل کننده ی MVC scaffolder آپدیت خواهد شد، بنابراین عبارت های Bind را برای روش های Edit تولید نمی کند.

کد جدید ماهیت موجود را خوانده و TryUpdateModel را فرا می خواند تا فیلدهای ورودی کاربر را در فرم پست شده ی داده آپدیت کند. بنابراین یک پرچم روی ماهیت تنظیم می کند که تغییر آن را نشان می دهد. وقتی که روش SaveChanges فراخوانده می شود، پرچم Modified باعث می شود که Entity Framework عبارت های SQL ایجاد کند و ردیف دیتابیس را آپدیت کند. Concurrency conflicts نادیده گرفته می شود و همه ی ستون های ردیف دیتابیس آپدیت می شوند، از جمله ستون هایی که کاربر تغییر نداده است. (آموزش بعدی نشان می دهد که چگونه به تضادهای همزمانی رسیدگی کنید و اگر می خواهید تنها فیلدهای انفرادی در دیتابیس آپدیت شوند می توانید ماهیت را روی Unchanged و فیلدهای انفرادی را روی Modified تنظیم کنید.)

به عنوان بهترین تمرین برای overposting، فیلدهایی که می خواهید توسط صفحه ی Edit قابل آپدیت شدن باشند، در پارامترهای TryUpdateModel لیست شده اند. در حال حاضر هیچ فیلد اضافه ای وجود ندارد که محافظت کنید، اما لیست کردن فیلدهایی که می خواهید model binder دسته بندی کند، این اطمینان را ایجاد می کند که اگر در آینده فیلدهایی به مدل داده اضافه کنید، به طور خودکار محافظت می شوند، تا اینکه به طور ضمنی آنها را در اینجا وارد کنید. به عنوان نتیجه ی این تغییرات نشان روش HttpPost Edit با روش ویرایش HttpGet یکی می باشد، بنابراین شما روش را به EditPost تغییرنام داده اید.

وضعیت های ماهیت و ضمیمه و روش های ذخیره ی تغییرات

کانتکست دیتابیس مسیر اینکه آیا ماهیت ها در حافظه با ردیف های متناظر خود در دیتابیس هماهنگ هستند یا نه حفظ می کند و این اطلاعات تعیین می کنند که در زمان فراخوانی روش SaveChanges چه اتفاقی می افتد. به عنوان مثال وقتی شما یک ماهیت جدید را به روش Add انتقال می دهید، وضعیت آن ماهیت به Added تنظیم می شود. سپس وقتی روش SaveChanges را فرامی خوانید، کانتکست دیتابیس یک فرمان SQL INSERT منتشر می کند. یک ماهیت ممکن است در یکی از وضعیت های زیر باشد.

Added. ماهیت هنوز در دیتابیس وجود ندارد. روش SaveChanges باید یک وضعیت INSERT منتشر کند.

Unchanged. هیچ کاری در مورد این روش توسط ماهیت SaveChanges نباید انجام شود. وقتی که شما یک ماهیت از دیتابیس را می خوانید، آن ماهیت با این وضعیت آغاز می شود.

Modified. همه یا بخشی از مقادیر پراپرتی ماهیت اصلاح شده اند. روش SaveChanges باید یک وضعیت UPDATE منتشر کند.

Deleted. ماهیت برای حذف علامتدار شد است. روش SaveChanges باید یک وضعیت DELETE منتشر کند.

Detached. ماهیت توسط کانتکست دیتابیس ردیابی نمی شود.

در برنامه ی دسکتاپ، تغییرات وضعیت عموما به طور خودکار تنظیم می شوند. در یک برنامه ی دسکتاپ یک ماهیت را می خوانید و تغییراتی را در برخی مقادیر پراپرتی آن اعمال می کنید. این باعث می شود که وضعیت ماهیت به طور خودکار به Modified تغییر یابد. سپس وقتی SaveChanges را فرامی خوانید Entity Framework یک وضعیت SQL UPDATE تولید می کند که تنها پراپرتی های حقیقی را که تغییر داده اید، آپدیت می کند.

حالت قطع اتصال برنامه های وب برای این ارتباط متداول اجازه داده نمی شود. DbContext که یک ماهیت را می خواند، پس از اجرای یک صفحه مورد بررسی قرار می گیرد. وقتی که روش فعالیت HttpPost Edit فراخوانده می شود، یک درخواست جدید ایجاد می شود و نمونه ی جدیدی از DbContext دارید. بنابراین مجبور هستید که وضعیت ماهیت را به طور دستی به Modified تنظیم کنید. سپس وقتی SaveChanges را فرامی خوانید، Entity Framework تمام ستون های ردیف ایتابیس را آپدیت می کند، زیرا کانتکست راهی برای شناسایی پراپرتی هایی که تغییر داده اید ندارد.

اگر شما بخواهید که SQL Update فقط فیلد هایی را آپدیت کند که کاربر تغییر داده، می توانیدمقادیر اصلی را به روش هایی ذخیره کنید (از جمله فیلدهای مخفی)، بنابراین وقتی روش HttpPostEdit فراخوانده می شود، در دسترس می باشند. سپس می توانید با استفاده از مقادیر اصلی یک ماهیت Student ایجاد کنید، با ورژن اصلی آن ماهیت روش Attach را فرابخوانید، مقادیر ماهیت را به مقادیر جدید آپدیت کنید و سپس SaveChanges را فرابخوانید.

کد HTML و Razor در Views\Student\Edit.cshtml مشابه آن چیزی است که در Create.cshtml مشاهده کردید و تغییری لازم نیست.

با انتخاب تب Students و سپس کلیک کردن بر روی هایپرلینک Edit، صفحه را اجرا کنید. برخی داده ها را تغییر داده و روی Save کلیک کنید. شما داده ی تغییر یافته را در صفحه ی ایندکس مشاهده می کنید.

آپدیت کردن صفحه ی Delete

در Controllers\StudentController.csکد الگو برای روش HttpGet Delete از روش Find برای بازیابی ماهیت Student انتخاب شده، استفاده می کند، همانطور که در روش های Details و Edit مشاهده کردید. به هرحال برای اجرای یک پیغام خطا، وقتی که SaveChanges با شکست مواجه می شود، برخی عملکردها را به این روش و ویو متناظر با آن اضافه می کنید. همانطور که برای آپدیت و ایجاد عملکردها مشاهده کردید، عملکردهای حذف دو روش فعالیت نیاز دارند. روشی که در پاسخ به درخواست Get فراخوانده می شود، ویویی را نمایش می دهد که به کاربر شانس تایید یا کنسل کردن عملکرد حذف را می دهد. اگر کاربر آن ا تایید کند، در هنگام اتفاق آن درخواست POST ایجاد می شود، که پس از آن روش HttpPost Delete فراخوانده می شود و سپس در واقع آن روش عملکرد حذف را انجام می دهد.

شما یک بلوک try-catch به روش HttpPost Delete اضافه خواهید کرد تا هر خطایی که ممکن است در هنگام آپدیت شدن دیتابیس اتفاق بیفتد، بررسی کنید. اگر یک خطا اتفاق بیفتد، روش HttpPost Delete روش HttpGet Delete را فرا می خواند و پاامتری را به آن منتقل می کند که نشان می دهد یک خطا اتفاق افتاده است. سپس روش HttpGet Delete صفحه ی تاییدیه را همراه با پیغام خطا دروباره نمایش می دهد و به کاربر شانس مجدد می دهد تا ان را کنسل کرده و یا دوباره امتحان کند.

۱٫ کد زیر را جایگزین روش فعالیت HttpGet Delete کنید که گزارش خطا را مدیریت می کند.

public ActionResult Delete(int? id، bool? saveChangesError=false)‎
‎{‎
‎ if (id == null)‎
‎ {‎
‎ return new ‎HttpStatusCodeResult(HttpStatusCode.BadRequest);‎
‎ }‎
‎ if (saveChangesError.GetValueOrDefault())‎
‎ {‎
‎ ViewBag.ErrorMessage = “Delete failed. Try again، and if ‎the problem persists see your system administrator.”;‎
‎ }‎
‎ Student student = db.Students.Find(id);‎
‎ if (student == null)‎
‎ {‎
‎ return HttpNotFound();‎
‎ }‎
‎ return View(student);‎
‎}‎

این کد یک optional parameter می پذیرد که نشان می دهد که روشی که آیا پس از شکست فراخوانده شد، تغییرات را ذخیره کرد. وقتی روش HttpGet Delete بدون شکست قبلی فراخوانده می شود، این پارامتر false می باشد. وقتی که در پاسخ به خطای آپدیت یک دیتابیس، توسط روش HttpPost Delete فراخوانده می شود، پارامتر trueمی باشد و پیغام خطا به ویو انتقال داده می شود.

۲٫ کد زیر را جایگزین روش فعالیت HttpPost Delete کنید که عملکرد حقیقی حذف را اجرا می کند و خطاهای آپدیت دیتابیس را می گیرد.

‎[HttpPost]‎
‎[ValidateAntiForgeryToken]‎
public ActionResult Delete(int id)‎
‎{‎
‎ try
‎ {‎
‎ Student student = db.Students.Find(id);‎
‎ db.Students.Remove(student);‎
‎ db.SaveChanges();‎
‎ }‎
‎ catch (DataException/* dex */)‎
‎ {‎
‎ //Log the error (uncomment dex variable name and add a line ‎here to write a log.‎
‎ return RedirectToAction(“Delete”، new { id = id، ‎saveChangesError = true });‎
‎ }‎
‎ return RedirectToAction(“Index”);‎
‎}‎

این کد ماهیت انتخاب شده را بازیابی می کند و سپس روش Remove را فرا می خواند تا وضعیت ماهیت را به Deleted تنظیم کند. وقتی که SaveChanges فراخوانده می شود، یک فرمان تولید می شود. شما همچنین نام روش فعالیت را از DeleteConfirmed به Delete تغییر داده اید. کد Scaffolded روش HttpPost Delete را با عنوان DeleteConfirmed نام گذاری کرد تا به روش HttpPost یک مشخصه ی خاص بدهد. (CLR روش های بارگذاری شده را ملزم می کند تا پارامترهای مختلفی داشته باشند.) اکنون ک مشخصه ها منحصر به فرد هستند، می توانید از عادت MVC استفاده کرده و از همان نام برای روش های حذف HttpPost و HttpGet استفاده کنید. اگر بهبود اجرا در یک برنامه ی سطح بالا ارجحیت دارد، می توانید با جایگزین کردن کد زیر به جای خطوط کد که روش های Find و Remove را فرا می خوانند، مانع از ردیف غیرضروری SQL برای بازیابی ردیف شوید.

Student studentToDelete = new Student() { ID = id };‎
db.Entry(studentToDelete).State = EntityState.Deleted;‎

این کد فقط با استفاده از مقدار اصلی اولیه یک ماهیت Student را نمونه می کند و سپس وضعیت ماهیت را به Deleted تنظیم می کند. این تمام کاری است که Entity Framework لازم است برای حذف ماهیت انجام دهد. همانطور که قبلا ذکر شد، روش HttpGet Delete داده را حذف نمی کند. اجرای یک عملکرد حذف در پاسخ به درخواست GET یک ریسک امنیتی ایجاد می کند.

در Views\Student\Delete.cshtml یک پیغام خطا بین تیتر h2 و h3 اضافه کنید، همانطور که در مثال زیر می بینید.

‎<h2>Delete</h2>‎

‎<p class=”error”>@ViewBag.ErrorMessage</p>‎

‎<h3>Are you sure you want to delete this?</h3>‎

صفحه را با انتخاب تب Students و کلیک کردن بر روی هایپرلینک Delete اجرا کنید.

۳٫ روی Delete کلیک کنید. صفحه ی Index بدون دانشجوی حذف شده نمایش داده می شود.

بستن اتصالات دیتابیس

برای بستن اطلاعات دیتابیس و آزاد کردن هر چه زودتر منابع، وقتی کار با آن را انجام دادید، نمونه ی کانتکست را بررسی کنید. به این خاطر است که کد scaffolded یک روش Dispose در انتهای گروه StudentController در StudentController.cs ارائه می دهد، همانطور که در مثال زیر نمایش داده شده است.

protected override void Dispose(bool disposing)‎
‎{‎
‎ db.Dispose();‎
‎ base.Dispose(disposing);‎
‎}‎

گروه Controller پایه تقریبا اینترفیس IDisposable را اجرا می کند، بنابراین، این کد به سادگی یه override به روش Dispose(bool) اضافه می کند تا به طور واضح نمونه ی کانتکست را نمایش دهد.

بررسی تبادلات

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

خلاصه

اکنون شما یک مجموعه ی کامل از صفحاتی را دارید که عملکردهای ساده ی CRUD را برای ماهیت های Student اجرا می کنند. شما از کمک کننده های MVC برای تولید عناصر UI برای فیلدهای داده استفاده کردید. در آموزش بعد، کاربرد صفحه ی Index را با اضافه کردن دسته بندی (sorting) و صفحه بندی (paging) گسترش خواهید داد.