11

I'm pretty new to MVC and i'm having troubles with cascade deleting. For my model I the following 2 classes:

    public class Blog
    {
        [Key]
        public int Id { get; set; }
        [Required]
        public string Name { get; set; }
        [DisplayFormat()]
        public virtual ICollection<BlogEntry> BlogEntries { get; set; }
        public DateTime CreationDateTime { get; set; }
        public string UserName { get; set; }
    }

    public class BlogEntry
    {
        [Key]
        public int Id { get; set; }
        [Required]
        public string Title { get; set; }
        [Required]
        public string Summary { get; set; }
        [Required]
        public string Body { get; set; }
        public List<Comment> Comments { get; set; }
        public List<Tag> Tags { get; set; }
        public DateTime CreationDateTime { get; set; }
        public DateTime UpdateDateTime { get; set; }
        public virtual Blog ParentBlog { get; set; }

    }

And for my controller I set he following on delete post back:

[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
    Blag blog = db.Blogs.Find(id);

    foreach (var blogentry in blog.BlogEntries)
    {
        //blogentry = db.BlogEntries.Find(id);
        db.BlogEntries.Remove(blogentry);
    }
    db.Blogs.Remove(blog);
    db.SaveChanges();
    return RedirectToAction("Index");
}

Problem is it wont work no matter what; I read this post but i seem to only work for models where the relation is one to one, so i'm lost here, i have search everywhere, and can't find the solution for this problem, if some could point out what i'm missing it would be really nice :), thanks in advance, and again, pardon my nooobness i'm just getting started, but wanted to tackle a big project to be able to learn a lot.

Community
  • 1
  • 1
Q_ro
  • 433
  • 2
  • 6
  • 18

2 Answers2

16

That is because EF by default does not enforce cascade deletes for optional relationships. The relationship in your model is inferred as optional.

You can add a non nullable scalar property(BlogId) of the FK

public class BlogEntry
{
    [Key]
    public int Id { get; set; }
    [Required]
    public string Title { get; set; }
    [Required]
    public string Summary { get; set; }
    [Required]
    public string Body { get; set; }
    public List<Comment> Comments { get; set; }
    public List<Tag> Tags { get; set; }
    public DateTime CreationDateTime { get; set; }
    public DateTime UpdateDateTime { get; set; }

    public int ParentBlogId { get; set; }

    public virtual Blog ParentBlog { get; set; }
}

Or configure this using fluent API

   modelBuilder.Entity<BlogEntry>()
            .HasRequired(b => b.ParentBlog)
            .WithMany(b => b.BlogEntries)
            .WillCascadeOnDelete(true);
Eranga
  • 32,181
  • 5
  • 97
  • 96
  • Yay ! :D, thanks it worked!, thanks a lot, i just wasn't aware of fluent API, but seems like a good way to do this stuff, by the way ¿can i get this behavior with data annotations?. – Q_ro Feb 11 '12 at 16:44
  • @Q_ro Data annotations has limited set of features. – Eranga Feb 12 '12 at 00:43
1

Not sure what you are trying to do here, but you have one record so not sure why you are trying to loop. Here is my delete code:

public ActionResult Delete(int id)
{
    try {
        Products products = context.Products.Single(x => x.productId == id);
        return View(products);
    }
    catch (Exception ex)
    {
        ModelState.AddModelError("", ex.Message);
        CompileAndSendError(ex);
        return View(new Products());
    }
}

//
// POST: /Products/Delete/5

[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
    try {
        Products products = context.Products.Single(x => x.productId == id);
        context.Products.Remove(products);
        context.SaveChanges();
        return RedirectToAction("Index");
    }
    catch (Exception ex)
    {
        ModelState.AddModelError("",ex.Message);
        CompileAndSendError(ex);
        return RedirectToAction("Index");
    }
}
Csaba Toth
  • 10,021
  • 5
  • 75
  • 121
davethecoder
  • 3,856
  • 4
  • 35
  • 66
  • Well, think of it this way, each product, have a category, i want to delete those categories too when i delete a product, 'cause, as it is now, if i delete a product, my categories will still be there on the database. – Q_ro Feb 11 '12 at 16:34
  • yeah but your code should only show code that contains categories, you should also have an enabled/disabled column for categories and items, essentially you should not really remove anything, but just mark as deleted this reduces problems later where an ID is referenced but no longer exists. if you want though you could get the category ID from the object, delete the category and then delete the original object but you should really be writing code to better deal with it rather than just removing everything :-) – davethecoder Feb 11 '12 at 16:42