38779

Missing something in “Delete” post method in MVC (EF 4.1)

Following this example .. http://msdn.microsoft.com/en-us/data/gg685489

I am running into issues with Delete functionality.

[HttpPost] public ActionResult Delete(int id, Blog blog) { try { using (var db = new BlogDataEntities()) { //Having issue here.. as soon as the next line is run in debug //mode .. it goes to catch.. and returns a view with null values. db.Entry(blog).State = System.Data.EntityState.Deleted; db.SaveChanges(); } return RedirectToAction("Index"); } catch { return View(); } }

In the parameters I checked 'blog' does not get the actual blog model that needs to be deleted. All the other methods work fine (Edit, Delete (get)..etc.. but Delete post fails. Am I missing something? thanks in advance for the help.

EDIT:

view code

@model DBFirstMVC.Models.Blog @{ ViewBag.Title = "Delete"; } <h2>Delete</h2> <h3>Are you sure you want to delete this?</h3> <fieldset> <legend>Blog</legend> <div class="display-label">Title</div> <div class="display-field">@Model.Title</div> <div class="display-label">BloggerName</div> <div class="display-field">@Model.BloggerName</div> </fieldset> @using (Html.BeginForm()) { <p> <input type="submit" value="Delete" /> | @Html.ActionLink("Back to List", "Index") </p> }

EDIT 2: Non Razor Code in view:

<% using (Html.BeginForm()) { %> <p> <input type="submit" value="Delete" /> | <%: Html.ActionLink("Back to List", "Index") %> </p> <% } %>

EDIT 3: (I tried in aspx)

<% using (Html.BeginForm()) { %> <p> <%=Html.DisplayForModel();%> //Tried Html.EditorForModel also.. <input type="submit" value="Delete" /> | <%: Html.ActionLink("Back to List", "Index") %> </p> <% } %>

FINAL EDIT (Corrected Solution)

@model DBFirstMVC.Models.Blog @{ ViewBag.Title = "Delete"; } <h2>Delete</h2> <h3>Are you sure you want to delete this?</h3> @using (Html.BeginForm()) { <p> <fieldset> <legend>Blog</legend> <div class="display-label">Title</div> <div class="display-field">@Model.Title</div> <div class="display-label">BloggerName</div> <div class="display-field">@Model.BloggerName</div> <input type="submit" value="Delete" /> | @Html.ActionLink("Back to List", "Index") </fieldset> </p> }

Answer1:

The context probably doesn't have an Entry for your Blog because it isn't attached to the Context.

You probably need to retrieve the Blog first and then mark it as deleted using the Entry method:

[HttpPost] public ActionResult Delete(int id, Blog blog) { try { using (var db = new BlogDataEntities()) { // retrieve the blog from the database var realBlog = db.Blogs.Find(blog.Id); // nothing to do here, just redirect if( realBlog == null ) return RedirectToAction("Index"); // since you have the entity just do this instead: db.Blogs.Remove(realBlog); db.SaveChanges(); } return RedirectToAction("Index"); } catch( Exception ) { return View(); } }

I don't really agree with the idea of using your entities as your models though. You should use View Models instead.

<strong>EDIT</strong>

Since you now are saying that Blog isn't being passed, try this:

@model Blog @using ( Html.BeginForm() ) { @Html.EditorForModel() <input type="submit" value="Delete" /> }

You weren't actually giving the model binder any of the details it needed to construct your model.

Answer2:

is it possible to try the following:

[HttpPost] public ActionResult Delete(Blog deletedBlog) { try { using (var db = new BlogDataEntities()) { // get blog entry from db context!! Blog blog = db.Blogs.Find(deletedBlog.Id); //Having issue here.. as soon as the next line is run in debug //mode .. it goes to catch.. and returns a view with null values. db.Entry(blog).State = System.Data.EntityState.Deleted; db.SaveChanges(); } return RedirectToAction("Index"); } catch(Exception e) { // should catch more specific exception // but catching 'e' should be a start return View(); } }

<strong>[Update]</strong> - pass in your Blog model from the view, tho as Dismissile says, you should really use a viewmodel, rather than the entity model for this purpose.

Also, you should catch the inner exception message and examine that for further clues.

Answer3:

The blog parameter in your Delete Action is null most likely because you are only posting the blog's id, not the entire blog object. I would either modify the Delete Action to accept just the id (per Dismissile's answer), or modify the Delete View to post the entire blog object and remove the id from the Action (since it belongs to the blog object):

[HttpPost] public ActionResult Delete(Blog blog) { try { using (var db = new BlogDataEntities()) { db.Entry(blog).State = System.Data.EntityState.Deleted; db.SaveChanges(); } return RedirectToAction("Index"); } catch { return View(); } }

Answer4:

I posted this in a few comments, but I felt it merited a separate answer for an "alternative".

Your controllers should be slim and adhere as best as possible to the single responsibility principle.

<strong>BlogController</strong>

public class BlogController : Controller { private BlogService blogService; public BlogService() { blogService = new BlogService(); } [HttpPost] public ActionResult Delete(int id) { // make sure the user has permission to delete before actually deleting // now that we know the user has permission if (blogService.Delete(id)) { return RedirectToAction("Index"); } else { return View(); } } }

Now you'll have a reusable service layer that adheres to the single responsibility principle.

<strong>BlogService</strong>

public class BlogService { private BlogDataEntities dc; public BlogService() { dc = new BlogDataEntities(); } public bool Delete(int Id) { try { var blog= (from b in dc.Blogs where Blog.ID == Id select b).First(); // blog doesn't exist, exit and return false. if( blog == null ) return false; // blog exists, remove it dc.Blogs.Remove(blog); // push the delete to the database SaveChanges(); // it worked, return true. return true; } catch(System.Exception ex) { // an error happened, handle it and return false. return false; } } // I like to keep my `SubmitChanges()` Separate in case I need to // stack up a few processes before hitting the database. public void SaveChanges() { dc.SaveChanges(); } }

Recommend

  • Large textinput makes http post fail
  • Using Orchard.Forms on the front-end with code only
  • multiple custom error message support per field by using parsley.js
  • set select list to current date using Jquery
  • font-face not showing up on Firefox
  • Use Greasemonkey to remove table
  • AngularJS error injector modulerr
  • css active on html inside php echo doesn't stay when click is left
  • How can I have equal heights for inner elements of flexbox grid/boxes/cards without using jQuery?
  • Contact form problem - I do receive messages, but no contents (blank page)
  • How can I make this modal persistent?
  • FileReader+canvas image loading problem
  • MongoDB in PHP using aggregate to group by _id is null not working
  • PHPUnit_Framework_TestCase class is not available. Fix… - Makegood , Eclipse
  • Adding a button at the bottom of a table view
  • Insert into database using onclick function
  • Display issues when we change from one jquery mobile page to another in firefox
  • Deselecting radio buttons while keeping the View Model in synch
  • Getting last autonumber in access
  • Why HTML5 Canvas with a larger size stretch a drawn line?
  • Submit form in a displaytag pagination
  • ActionScript 2 vs ActionScript 3 performance
  • To display the title for the current loaction in map in iphone
  • Delete MySQLi record without showing the id in the URL
  • GridView Sorting works once only
  • Traverse Array and Display in markup
  • Cannot Parse HTML Data Using Android / JSOUP
  • trying to dynamically update Highchart column chart but series undefined
  • How to set the response of a form post action to a iframe source?
  • Java static initializers and reflection
  • How to get Windows thread pool to call class member function?
  • IndexOutOfRangeException on multidimensional array despite using GetLength check
  • unknown Exception android
  • costura.fody for a dll that references another dll
  • Observable and ngFor in Angular 2
  • How to Embed XSL into XML
  • UserPrincipal.Current returns apppool on IIS
  • Unable to use reactive element in my shiny app
  • Conditional In-Line CSS for IE and Others?
  • java string with new operator and a literal